Uso de chaves {} como argumentos para comandos e suas opções

11

Exemplos

Recentemente, encontrei exemplos de uso de pares de chaves {}, sem nada entre as chaves de abertura e fechamento, como argumentos para comandos e até para suas opções:

cat foo | xargs -I{} echo {}

find . -size 0 -exec rm -i {} \;

Sem documentação

Meu problema é que não consigo encontrar uma documentação no Manual do GNU Bash que descreva o uso {}desse contexto, como nos exemplos acima.

Eu não acho que seja uma expansão de parâmetro , porque um cifrão deve preceder os colchetes em uma expansão de parâmetro como em ${}.

Também não pode ser uma expansão de chave , porque assume a forma de {x..y[..incr]}, onde xe ynão é opcional.

Também não pode ser um agrupamento de comandos , porque {}é usado como argumentos.

Questões

  1. O que um par de chaves anexas {}significa, em geral, como argumento para qualquer comando que a aceite?

  2. Onde posso encontrar uma documentação que descreva o uso de {}como argumentos?

Niko Gambt
fonte
Alguns comandos têm essas opções {}- o que significa targetsagir, com o findcomando, é remover / rmencontrar arquivos.
Tuyen Pham

Respostas:

16

Esses aparelhos encaracolados são deixados sozinhos pelo bash; eles pertencem finde xargs, respectivamente, e são descritos em suas páginas de manual.

man find

-exec comando ;

Executar comando ; true se 0 status for retornado. Todos os seguintes argumentos a serem encontrados são considerados argumentos para o comando até que um argumento consistindo em ;seja encontrado. A cadeia {}é substituída pelo nome do arquivo atual sendo processado em todos os lugares em que ocorre nos argumentos do comando, não apenas nos argumentos em que está sozinho, como em algumas versões do find. Ambas as construções podem precisar ser escapadas (com a \) ou citadas para protegê-las da expansão pelo shell. Veja a seção EXEMPLOS para exemplos de uso da -execopção. O comando especificado é executado uma vez para cada arquivo correspondente. O comando é executado no diretório inicial. Existem problemas de segurança inevitáveis ​​em torno do uso da -exec ação; você deve usar a -execdiropção.

-exec comando {} +

Essa variante da -execação executa o comando especificado nos arquivos selecionados, mas a linha de comando é criada anexando cada nome de arquivo selecionado no final; o número total de invocações do comando será muito menor que o número de arquivos correspondentes. A linha de comando é construída da mesma maneira que xargscria suas linhas de comando. Apenas uma instância de {}é permitida dentro do comando. O comando é executado no diretório inicial. Se findencontrar um erro, isso às vezes pode causar uma saída imediata; portanto, alguns comandos pendentes podem não ser executados. Essa variante -execsempre retorna true.

-execdir comando ;

-execdir comando {} +

Como -exec, mas o comando especificado é executado no subdiretório que contém o arquivo correspondente, que normalmente não é o diretório no qual você começou a localizar. Esse é um método muito mais seguro para chamar comandos, pois evita condições de corrida durante a resolução dos caminhos para os arquivos correspondentes. Assim como a -exec ação, a + forma de -execdir criará uma linha de comando para processar mais de um arquivo correspondente, mas qualquer chamada de comando dada listará apenas os arquivos que existem no mesmo subdiretório. Se você usar esta opção, assegure-se de que sua $PATHvariável de ambiente não faça referência.; caso contrário, um invasor poderá executar qualquer comando que desejar, deixando um arquivo com nome apropriado em um diretório no qual você executará -execdir. O mesmo se aplica a ter entradas $PATHvazias ou que não sejam nomes de diretório absolutos. Se findencontrar um erro, isso às vezes pode causar uma saída imediata; portanto, alguns comandos pendentes podem não ser executados. O resultado da ação depende se +a ;variante ou a está sendo usada; -execdir O comando {} + sempre retorna true, enquanto o -execdir comando {} ; retorna true somente se o comando retornar 0.

man xargs

-I replace-str

Substitua ocorrências de replace-str nos argumentos iniciais pelos nomes lidos na entrada padrão. Além disso, espaços em branco não citados não finalizam itens de entrada; em vez disso, o separador é o caractere de nova linha. Implica -xe -L 1.

-i[ substituir-str ], --replace[ =substituir-str ]

Esta opção é sinônimo de -Ireplace-str, se replace-str for especificado. Se o argumento replace-str estiver ausente, o efeito será o mesmo que -I{}. Esta opção está obsoleta; use em -Ivez disso.

Edit: e aqui POR QUE o bash ignora os chavetas:

man bash

{ Lista; }

A lista é simplesmente executada no ambiente atual do shell. A lista deve ser finalizada com uma nova linha ou ponto e vírgula. Isso é conhecido como um comando de grupo. O status de retorno é o status de saída da lista. Observe que, diferentemente dos metacaracteres ( e ) , { e } são palavras reservadas e devem ocorrer onde uma palavra reservada pode ser reconhecida. Como eles não causam uma quebra de palavra, eles devem ser separados da lista por espaços em branco ou outro metacaractere do shell.

Para enfatizar: a lista deve ser finalizada com uma nova linha ou ponto e vírgula .

consertar
fonte
1
Obrigado! Estou irritado que quem escreveu man xargsnem se deu ao trabalho de explicar o que {}realmente significa, nem o autor redirecionou (sem trocadilhos) o leitor para a explicação -execna página do manual find.
Niko Gambt 15/01/19
@NikoGambt - Eu simpatizo ...
tink
5
@NikoGambt Bem, {} realmente não significa nada para xargs, exceto por ser o valor padrão para -i, que está obsoleto. Não tenho certeza de qual explicação é necessária além disso. No exemplo que você postou, poderia muito bem ter sido xargs -Iab echo ab; é uma escolha puramente arbitrária.
usar o seguinte código
@ Random832 Depois de fazer mais alguns testes -I, agora entendo o que essa opção realmente faz. Sim, {}é arbitrário, como você disse. Eu só estava confuso com a explicação If the replace-str argument is missing, the effect is the same as -I{}. Se -Isem argumento fosse o mesmo que -I{}, então cat foo | xargs -I echo {}produziria o mesmo resultado que em execução cat foo | xargs -I{} echo {}. No entanto, eles não são os mesmos. O primeiro é um erro, e o que mais me confundiu foi a mensagem de erro xargs: {}: No such file or directory, mas isso se deve apenas à implementação.
Niko Gambt 15/01/19
1
@NikoGambt -I(I maiúsculo) não pode ser executado sem um argumento. O argumento para -Iera echo. Esta é a principal diferença entre -Ie -i(ea razão -i é obsoleto, uma vez que as opções com argumentos não obrigatórios são incomuns e confundindo)
Random832