Difference between '{}' and {} in find command?
In the documentation, I see usage both ways:
find . -type f -exec file '{}' \;
find repo/ -exec test -d {}/.svn -o -d {}/.git -o -d {}/CVS ; \
For the bash
shell, '{}'
and {}
are interchangeable. This is not be the case with all shells (such as fish
).
Putting the argument in single quotes explicitly indicates that the curly braces should be sent to find
. Depending on the usage, the bash shell sometimes substitutes the contents of curly brackets.
As seen below, bash does not substitute empty brackets, and they get passed to the command. For the find
command, it doesn't matter.
$ echo {}
{}
$ echo {1}
{1}
$ echo {1,3}
1 3
$ echo '{1,3}'
{1,3}
With almost all shell interpreters available, there is absolutely no difference between '{}'
and {}
.
The single quotes are normally used to protect the embedded string from being substituted by something else, for example:
-
'a b'
is a single three characters parameter, without the quotes that would be two single character parameters -
'$b'
is a literally the dollar sign followed by the letter b, without the quote that would be whatever the b variable contains and possibly nothing if unset -
'!!'
are litteral exclamation marks while unquoted and with some interactive shells, they would expand to the last command put in the history -
'*'
is a litteral asterisk, unquoted it would be replaced by the list of non hidden filenames in the current directory.
As neither the POSIX standard nor the mainstream shells (sh
(Bourne), ksh
, bash
, ash
, dash
, zsh
, csh
, tcsh
) expand {}
to something else, the quotes are not required.
However, there is an exotic shell, named fish
, which happen to expand {}
as an empty string, e.g.:
> ps -p %self
PID TTY TIME CMD
5247 pts/1 00:00:00 fish
> echo a {} b '{}'
a b {}
That is probably the reason why GNU find
documentation suggest to protect {}
against interpretation with quotes or backslashes.
For most users (particularly those using POSIX shells), there’s no difference.
According to the Example section of the man page for GNU find
:
Notice that the braces are enclosed in single quote marks to protect them from interpretation as shell script punctuation.
I think the author(s) of the GNU man page are erring on the side of caution but I note that not all the examples in their man page quote the braces. These examples from the official GNU find documentation also omit the quoting.
In the examples from the POSIX / Single UNIX Specification the braces are not quoted when used with the -exec
option.
With a POSIX shell, parameter expansion only occurs when there are special parameters enclosed within the braces – but not with empty braces.
The Bash shell includes brace expansion as a (non-portable) feature, but such patterns are only expanded when a comma or dots are included within the braces. Bash also uses braces for command grouping, but this doesn’t occur unless there actually is a group of commands within the brace.
Finally, I tried running find -exec ls -l {} \;
in sh
, dash
and tcsh
but none of these shells expanded the {}
into anything else. As others have pointed out, the fish
shell treats {}
specially but this is not a POSIX shell (which its creators and users consider to be an advantage). It does no harm to quote the braces but lazy typists who don’t use the fish shell shouldn’t feel guilty about omitting them.
This depends on your shell's syntax. When in doubt, echo it!
Run this
echo '{}'
and this.
echo {}
If they produce the same output, then the answer for your shell is yes. As others have noted, it will at least be yes in bash and no in fish. The output, is what you should consult a given command's manpage for.
If you want to get handy, you can even prefix echo
to a whole command line, to see the actual command, with all its arguments, that your shell would actually invoke. Beware though, that the list comprising the command plus arguments is a true array of strings, each possibly empty or with whitespace, yet echo prints it ambiguously as a space separated list.
As can be verified with this slightly more verbose echo command (showing guillemet-quoted arguments),
#!/bin/sh
for a in "$@"; do
printf '«%s» ' "$a"
done
echo ''
typing this on the command line,
find 'My Documents and Settings' -type f -exec file {} \;
means this to bash:
«find» «My Documents and Settings» «-type» «f» «-exec» «file» «{}» «;»
and this in fish:
«find» «My Documents and Settings» «-type» «f» «-exec» «file» «» «;»
As a general advice, it never hurts to quote.