Shell – GNU find and masking the {} for some shells – which

findquotingshellxargs

The man page for GNU find states:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

That's from the man to find (GNU findutils) 4.4.2.

Now I tested this with bash and dash, and both don't need to have the {} being masked. Here is a simple test:

find /etc -name "hosts" -exec md5sum {} \; 

Is there a shell, for which I really need to mask the braces? Note, that it doesn't depend upon whether the file found contains a blank (invoked from bash):

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

This changes if the found file is passed to a subshell:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

which can be solved by:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

in contrast to:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

but that's not what the man page is talking about, is it? So which shell treats {} in a different way?

Best Answer

Summary: If there ever was a shell that expanded {}, it's really old legacy stuff by now.

In the Bourne shell and in POSIX-compliant shells, braces ({ and }) are ordinary characters (unlike ( and ) which are word delimiters like ; and &, and [ and ] which are globbing characters). The following strings are all supposed to be printed literally:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

A word consisting of a single brace is a reserved word, which is only special if it is the first word of a command.

Ksh implements brace expansion as an incompatible extension to the Bourne shell. This can be turned off with set +B. Bash emulates ksh in this respect. Zsh implements brace expansion as well; there it can be turned off with set +I or setopt ignore_braces or emulate sh. None of these shells expand {} in any case, even when it's a substring of a word (e.g. foo{}bar), due to the common use in arguments to find and xargs.

Single Unix v2 notes that

In some historical systems, the curly braces are treated as control operators. To assist in future standardisation activities, portable applications should avoid using unquoted braces to represent the characters themselves. It is possible that a future version of the ISO/IEC 9945-2:1993 standard may require that { and } be treated individually as control operators, although the token {} will probably be a special-case exemption from this because of the often-used find {} construct.

This note was dropped in subsequent versions of the standard; the examples for find have unquoted uses of {}, as do the examples for xargs. There may have been historical Bourne shells where {} had to be quoted, but they would be really old legacy systems by now.

The csh implementations I have at hand (OpenBSD 4.7, BSD csh on Debian, tcsh) all expand {foo} to foo but leave {} alone.