O GNU encontra e mascara o {} para algumas conchas - quais?

34

A página de manual 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 {}mascaramento. Aqui está um teste simples:

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

Existe uma concha, para a qual eu realmente preciso mascarar o aparelho? Observe que isso não depende se o arquivo encontrado contém um espaço em branco (chamado a partir 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 é disso que a página de manual está falando, é? Então, qual shell trata {}de uma maneira diferente?

Usuário desconhecido
fonte
Volker Siegel: Sua edição pode ter acontecido com boas intenções, mas eu verifiquei meu manual de localização atual e suas correções estão erradas. Você também perdeu a oportunidade de resumir suas edições, o que é um mau hábito. Desculpe, companheiro.
usuário desconhecido
Oh, obrigado por reverter se algo quebrou. Eu estava lembrando que o compilador de texto que gera o formato da página de manual usado para gerar essas "aspas tipográficas" como um artefato da definição de renderização. Também pode renderizar para o TeX para uma formatação perfeita de impressão. Notei as aspas porque elas confundiam o destaque da sintaxe. Eu assumi que a primeira citação incomum está errada quando usada em código, e ainda assumo isso. Observe que as duas alterações estavam no texto da descrição, não no código. Portanto, se os vemos como tipografia - renderização estética - eles estão certos.
Volker Siegel
Parece que, na renderização da saída de informações, a mesma citação é usada nos dois lados. Não há dúvida de que a minha alteração tornou diferente do original, você está certo. Mas isso causou algum problema? (Eu considero a primeira citação como um bug na definição homem de renderização, é o único caso de tipografia, tanto quanto eu sei.)
Volker Siegel
Acabei de verificar: `{} 'não funciona na linha de comando. Isso é tecnicamente correto, mas não gosto que um usuário desavisado receba um erro estranho ao tentar copiá-lo e colá-lo.
Volker Siegel
@VolkerSiegel: É um texto em prosa, não código, então o que o usuário deve copiar e colar aqui? E é uma citação da página de manual de 2011. Não vejo nenhum valor corrigindo a passagem para apontar por que fiz correções na página de manual. O tópico é bastante complicado. Se essa fosse sua pergunta, eu não tentaria convencê-lo, para citar a página de manual com precisão, mas para a minha pergunta, não estou com disposição para fazer compromissos. Citação é citação.
usuário desconhecido

Respostas:

26

Resumo : se já houve um shell que se expandiu {}, é realmente um legado antigo até agora.

No shell Bourne e em shells compatíveis com POSIX, chaves ( {e }) são caracteres comuns (diferentes (e )que são delimitadores de palavras como ;e &, [e ]quais são caracteres brilhantes). As seguintes seqüências de caracteres devem ser impressas literalmente:

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

Uma palavra que consiste em uma única chave é uma palavra reservada , que só é 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. O Bash emula o ksh a esse respeito. O Zsh também implementa expansão de chaves; lá pode ser desligado com set +Iou setopt ignore_bracesou emulate sh. Nenhum desses shells se expande {}em nenhum caso, mesmo quando é uma substring de uma palavra (por exemplo foo{}bar), devido ao uso comum nos argumentos para finde xargs.

O Unix v2 único observa que

Em alguns sistemas históricos, as chaves são tratadas como operadores de controle. Para ajudar em futuras atividades de padronização, os aplicativos portáteis devem evitar o uso de chaves sem aspas para representar os próprios caracteres. É possível que uma versão futura da norma ISO / IEC 9945-2: 1993 possa exigir isso {e }ser tratada individualmente como operadores de controle, embora o token {}provavelmente seja uma isenção de caso especial disso por causa da find {}construção frequentemente usada .

Esta nota foi descartada nas versões subsequentes do padrão; os exemplos parafind ter usos sem aspas de {}, assim como os exemplos paraxargs . Pode ter havido {}citações históricas de Bourne onde precisavam ser citadas, mas agora seriam sistemas legados realmente antigos.

As implementações do csh que tenho em mãos (OpenBSD 4.7, BSD csh no Debian , tcsh) se expandem {foo}para fooapenas deixar em {}paz.

Gilles 'SO- parar de ser mau'
fonte
11
@geekosaur: Apenas um pequeno subconjunto de remarcações funciona nos comentários . Não sei o que você está tentando dizer. Se for sobre a expansão de chaves de ksh et al, leia meu parágrafo começando com "O Ksh implementa a expansão de chaves como uma extensão incompatível".
Gilles 'SO- stop be evil'
2
Isso foi bash(veja $BASH_VERSION). A expansão da cinta está muito viva e bem.
Geekosaur
2
Esse era o ponto. A {}sintaxe teve origem csh, mas foi {}expandida para a sequência vazia. Os reservatórios mais recentes reconhecem que isso não faz sentido, mas ainda existem alguns velhos cshpor aí.
Geekosaur #
11
@geekosaur: Você pode dizer qual versão csh específica em qual plataforma específica? Eu preferiria testá-lo eu mesmo (se possível no linux) ou ter certeza de que a pessoa testou ele mesmo.
desconhecido usuário
11
@geekosaur, {}fooexpandiria para foo, mas {}expandiria para {}(exceto quando dentro de backticks, mas a citação não ajudaria) e foi documentado como tal. Eu verifiquei para o csh de 2BSD (primeira versão), 2.79BSD, 2.8BSD e 2.11BSD.
Stéphane Chazelas
12

O {}necessário para ser citado nas versões do fishshell anteriores à 3.0.0.

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

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

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

Provavelmente, essas não são as conchas que os autores desse GNU acham que a documentação tinha em mente quando escreveram esse texto desde que fishfoi lançado pela primeira vez em 2005 (enquanto esse texto ou similar já existia em 1994) e rcnão era originalmente um shell Unix.

Existem alguns rumores de que algumas versões csh(o shell que introduziu a expansão de chaves) exigiam isso. Mas é difícil dar crédito àqueles desde o primeiro lançamento do csh2BSD não. Aqui, como testado em um emulador PDP11:

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

E a página de manual do 2BSD cshafirma claramente :

Como um caso especial, `{',`}' e `{} 'são passados ​​imperturbáveis.

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

Poderia ter sido contornar alguns erros em algumas versões. Ainda com esse csh 2BSD (isso é 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

A citação não ajuda, porém:

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

Você pode citar toda a substituição do comando:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

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

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

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

(embora esse tipo de finduso não seja portátil, pois alguns finds se expandem apenas {}por conta própria).

Stéphane Chazelas
fonte
1

Em uma palavra csh. bashe outros shells modernos reconhecem que o usuário provavelmente não está solicitando uma expansão de chave nula. (Moderno cshé realmente tcshe também pode lidar com {}sanidade a essa altura.)

geekosaur
fonte
É bom ouvir isso, mas estou pedindo o oposto, uma concha que não lida com ela de maneira saudável.
desconhecido usuário
Você está assumindo que alguém entraria e extrairia a referência da página de informações para citações extras apenas porque todos os sistemas Linux são mais novos csh. Nem todo mundo executa utilitários GNU no Linux; de fato, é bastante comum instalá-los em sistemas Unix comerciais mais antigos, cujos comandos agrupados são limitados. (A substituição cshnesses sistemas é menos provável, porque os scripts do sistema podem depender das idiossincrasias do original cshe, mesmo que todos os usuários tenham sido configurados para usar um mais novo csh, rootquase certamente precisará permanecer a versão em pacote.)
geekosaur
2
Não. Estou em um debate com um cara que diz que em nosso wiki devemos dar conselhos para usar "{}" o tempo todo, porque a página de manual diz isso. E agora eu gostaria de saber se existe um shell que não estou usando, como ksh, zsh, tcsh, csh ou XYZsh, que eu não conheço, para o qual essa afirmação é verdadeira ou se honestamente posso assumir que não existe. Se houver shells para diferentes Unixes que precisem do "{}", essa seria uma boa explicação para a frase ainda estar na página do manual, mas não é apropriada como conselho para iniciantes no Linux.
desconhecido usuário
Agora estou me perguntando se pdkshfaz a coisa certa ... embora a resposta correta para isso seja provavelmente "real kshé o software livre atualmente".
geekosaur
4
Pdksh, como mksh, ksh93, bash e zsh, só expande chaves quando há uma vírgula no meio (ou ..para ksh93, bash e zsh). Somente se expande (t) csh {foo}para foo, e até mesmo deixa {}sozinho (pelo menos no recente BSD 's).
Gilles 'SO- stop be evil'