Observar:
mark@L-R910LPKW:~$ echo a b | xargs -d' ' -I{} bash -c 'echo {} 1'
a 1
b
bash: line 2: 1: command not found
mark@L-R910LPKW:~$
O que está acontecendo?
Observar:
mark@L-R910LPKW:~$ echo a b | xargs -d' ' -I{} bash -c 'echo {} 1'
a 1
b
bash: line 2: 1: command not found
mark@L-R910LPKW:~$
O que está acontecendo?
o que deu errado
b
aparece na saída, então foi processado, mas não da maneira que você esperava.Como primeiro passo, peça ao bash para dizer o que ele vê: passe a
-x
opção para habilitar seus rastreamentos.Portanto, o bash foi invocado pela primeira vez na linha de código
echo a 1
conforme o esperado. Mas a próxima linha éecho b
e nãoecho b 1
como você presumivelmente esperava. E há uma linha extra com1
. Por que?Bem, você disse aos xargs para dividir em espaços. E você passou a entrada
a b
where
is a newline. Então xargs viu que a entrada contém dois fragmentos:a
eb
. Conforme instruído, xargs chamou bash para cada fragmento: primeiro para executarecho a 1
, depois para executarecho b1
.Como fazer certo
Algumas versões
find
permitemxargs
que você incorpore{}
em um fragmento de shell. Isso quase sempre é uma má ideia, que irá quebrar com alguns nomes de arquivo ou outros dados, e geralmente é uma vulnerabilidade de segurança. Passe os dados como um argumento separado.É possível usar `find -exec sh -c` com segurança?
Como Gilles mencionou em sua resposta , a
-d ' '
opção GNU xargs faz com que considere o espaço, e apenas o espaço, como separador, deixando a nova linha como parte dos dados, aqui incorporados ao seu código shell como as próprias letras. Isso pode não ser o que você quer. (Provavelmente, o uso mais comum para-d
é-d '\n'
dizer a ele para usar apenas as linhas como estão, sem nenhum processamento adicional que, por exemplo,-L
faz.)Se, em vez disso, você deseja obter cada palavra separada por espaços em branco como um item separado, uma opção é utilizar o comportamento padrão em que divide itens em espaços em branco, portanto, isso funciona diretamente:
Apenas observe que ele também processa aspas e barras invertidas (de uma forma ligeiramente diferente do shell), então isso não é o mesmo que usar espaços em branco apenas como separador. A entrada
a "b c"
produziria os itensa
eb c
.Ou você pode usar
-d
withtr
para pré-processar a entrada e dobrar todos os caracteres que deseja usar como separadores em um único caractere:No entanto,
-d
não é padrão e acho que implementado apenas no GNU xargs, então você pode querer usar-0
o que tem suporte mais amplo:Em qualquer caso, evite incorporar o valor diretamente no trecho de shell, pois isso é inseguro e impossível de funcionar corretamente com valores arbitrários.