Parece-me que todas as respostas existentes nesta página estão incorretas, incluindo a marcada como correta. Isso decorre do fato de que a pergunta é ambígua.
Resumo: Se você deseja executar o comando "exatamente uma vez para cada linha de entrada fornecida", passando a linha inteira (sem a nova linha) para o comando como um único argumento, esta é a melhor maneira compatível com UNIX:
... | tr '\n' '\0' | xargs -0 -n1 ...
O GNU xargs
pode ou não ter extensões úteis que permitem eliminar tr
, mas elas não estão disponíveis no OS X e em outros sistemas UNIX.
Agora, para a longa explicação…
Há dois problemas a serem considerados ao usar o xargs:
- como ele divide a entrada em "argumentos"; e
- quantos argumentos para passar o comando filho por vez.
Para testar o comportamento do xargs, precisamos de um utilitário que mostre quantas vezes ele está sendo executado e com quantos argumentos. Não sei se existe um utilitário padrão para fazer isso, mas podemos codificá-lo facilmente no bash:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
Supondo que você o salve como show
em seu diretório atual e o torne executável, veja como funciona:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Agora, se a pergunta original é realmente sobre o ponto 2. acima (como eu acho que é, depois de ler algumas vezes) e deve ser lida assim (alterações em negrito):
Como posso fazer xargs executar o comando exatamente uma vez para cada argumento de entrada fornecido? Seu comportamento padrão é dividir a entrada em argumentos e executar o comando o menor número de vezes possível , passando vários argumentos para cada instância.
então a resposta é -n 1
.
Vamos comparar o comportamento padrão do xargs, que divide a entrada em branco e chama o comando o menor número de vezes possível:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
e seu comportamento com -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Se, por outro lado, a pergunta original era sobre a divisão de entradas do ponto 1. e era para ser lida assim (muitas pessoas que vêm aqui parecem pensar que é esse o caso, ou estão confundindo as duas questões):
Como posso fazer xargs executar o comando com exatamente um argumento para cada linha de entrada fornecida? Seu comportamento padrão é dividir as linhas em torno do espaço em branco .
então a resposta é mais sutil.
Alguém poderia pensar que isso -L 1
poderia ajudar, mas acontece que não muda a análise de argumentos. Ele executa o comando apenas uma vez para cada linha de entrada, com tantos argumentos quanto nessa linha de entrada:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Não apenas isso, mas se uma linha termina com espaço em branco, ela é anexada à seguinte:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Claramente, -L
não se trata de mudar a maneira como o xargs divide a entrada em argumentos.
O único argumento que faz isso de uma forma multiplataforma (excluindo extensões GNU) é -0
, que divide a entrada em torno de bytes NUL.
Depois, basta traduzir novas linhas para NUL com a ajuda de tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Agora, a análise do argumento parece correta, incluindo o espaço em branco à direita.
Por fim, se você combinar essa técnica -n 1
, obterá exatamente uma execução de comando por linha de entrada, qualquer que seja sua entrada, que pode ser outra maneira de analisar a questão original (possivelmente a mais intuitiva, considerando o título):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
find /path -type f -delete
seria ainda mais eficiente :)