GNU encontra e mascara o {} para algumas shells - qual?

34

A página man do GNU encontra estados:

-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. 

Isso é do homem para find (GNU findutils) 4.4.2.

Agora eu testei isso com bash e dash, e ambos não precisam ter o {} sendo mascarado. Aqui está um teste simples:

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

Existe um shell, para o qual eu realmente preciso mascarar as chaves? Note que não depende se o arquivo encontrado contém um espaço em branco (invocado do bash):

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

Isso muda se o arquivo encontrado for passado para um 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

que pode ser resolvido por:

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

em contraste com:

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

mas não é isso que a página man está falando, é? Então, qual shell trata {} de uma maneira diferente?

    
por user unknown 05.03.2011 / 15:55

3 respostas

27

Resumo : Se alguma vez houve um shell que expandiu {} , este é um legado antigo.

No shell Bourne e em shells compatíveis com POSIX, chaves ( { e } ) são caracteres comuns (ao contrário de ( e ) , que são delimitadores de palavras como ; e & e [ e ] que são caracteres globbing). As seguintes strings devem ser impressas literalmente:

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

Uma palavra que consiste em uma chave única é uma palavra reservada , que é apenas especial se for a primeira palavra de um comando.

O Ksh implementa a expansão de chaves como uma extensão incompatível para o shell Bourne. Isso pode ser desativado com set +B . Bash emula ksh a esse respeito. Zsh implementa a expansão de contraventamento também; Lá, ele pode ser desativado com set +I ou setopt ignore_braces ou emulate sh . Nenhum desses shells expande {} em nenhum caso, mesmo quando é uma subseqüência de uma palavra (por exemplo, foo{}bar ), devido ao uso comum em argumentos para find e xargs .

Unix único v2 observa que

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.

Esta nota foi descartada em versões subsequentes do padrão; Os exemplos de find têm usos não cotados de {} , assim como o < Exemplos de xargs . Pode ter havido shells históricos de Bourne, onde {} tinha que ser citado, mas eles seriam realmente antigos sistemas legados até agora.

As implementações do csh que tenho à mão (OpenBSD 4.7, BSD csh no Debian , tcsh) expandem {foo} para foo mas deixe {} sozinho.

    
por 05.03.2011 / 17:21
12

O {} precisa ser citado no fish shell.

$ fish -c 'echo find -exec {} \;'
find -exec  ;

E no shell rc (também akanga com base em rc , mas não em es ):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

Esses provavelmente não são os shells que os autores do GNU acham que a documentação tinha em mente quando escreveram esse texto desde que fish foi lançado em 2005 (enquanto aquele texto ou similar já existia em 1994) e rc foi não originalmente um shell Unix.

Existem alguns rumores de algumas versões de csh (o shell que introduziu a expansão de chaves) que precisam dele. Mas é difícil dar crédito a eles desde o primeiro lançamento do csh no 2BSD. Aqui como testado em um emulador PDP11:

# echo find -exec {} \;
find -exec {} ;

E a página man do 2BSD csh afirma claramente :

As a special case '{', '}' and '{}' are passed undisturbed.

Então eu acharia muito estranho se uma versão subseqüente do csh ou tcsh quebrasse mais tarde isso.

Poderia ter sido para contornar alguns erros em algumas versões. Ainda com esse csh 2BSD (que é o mesmo em 2.79BSD, 2.8BSD, 2.11BSD):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo 'echo foo {} bar'
echo 'echo foo {} bar'
echo foo {} bar
foo  bar

As citações não ajudam:

# echo 'echo foo '{}' bar'
echo 'echo foo '{}' bar'
echo foo {} bar
foo  bar

Você pode citar toda a substituição de comandos:

# echo "'echo foo {} bar'"
echo 'echo foo {} bar'
echo foo {} bar
foo {} bar

Mas isso está passando um argumento para esse eco externo.

Em csh ou tcsh , você precisa citar o {} quando não está sozinho, como em:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(embora esse tipo de uso de find não seja portátil, pois alguns find s expandem apenas {} quando estão sozinhos).

    
por 06.12.2015 / 22:06
1

Em uma palavra, csh . bash e outros shells modernos reconhecem que o usuário provavelmente não está pedindo uma expansão de chave nula. (Modern csh é realmente tcsh e também pode manipular {} até agora.)

    
por 05.03.2011 / 16:08