Diferença entre "xargs" e substituição de comando?

14

Em muitos casos, uso substituição de comando em vez de xargs. Por exemplo, rm $(ls)é o mesmo quels | xargs rm

Quais são realmente as diferenças entre eles?

Acho que uma das diferenças é que a substituição de comandos é executada no subshell enquanto xargsé executada no shell atual, mas não tenho certeza.

Por favor, liste as diferenças.

Sinoosh
fonte

Respostas:

9

Uma diferença é que, ao usar substituição de comando em vez de um canal, o tamanho dos dados transmitidos é limitado pelo tamanho do buffer de comando, portanto, ele é truncado em alguns casos sem aviso. Isso também significa que toda a saída do comando deve ser produzida e armazenada na memória antes de ser passada para o próximo comando; portanto, para saídas grandes, você pode usar muito mais memória do que o necessário.

Outro problema com o primeiro método é que a saída é dividida em espaço em branco, portanto, você não pode manipular nomes de arquivos com espaços neles. xargstambém é afetado pelo problema de espaço em branco, mas pode ser corrigido alterando o delimitador usado. Para tratar adequadamente os nomes de arquivos, a propósito, você precisaria usar o byte nulo como um delimitador no segundo exemplo.

Uma terceira questão é que os globs são expandidos; portanto, se um arquivo tiver asteriscos ou pontos de interrogação em seu nome, haverá resultados inesperados.

Você pode encontrar uma boa discussão sobre o assunto aqui: http://mywiki.wooledge.org/ParsingLs

A sintaxe correta seria

echo rm *

ou se você deve usar xargs,

find . -maxdepth 1 -print0 | xargs -0 echo rm

Remova echoquando a saída parecer correta.

user000001
fonte
1
@Sinoosh: xargstambém é executado em um subshell devido ao pipe, a menos que você ative shopt -s lastpipe; nesse caso, ele será executado no shell atual. Eu não acho que a execução em um subshell seja um problema, neste caso, pois você não está alterando nenhuma variável.
user000001
1
@ Sinoosh: Para passar argumentos um por um, você pode usar a -lbandeira, como find . -maxdepth 1 -print0 | xargs -0 -l rm. Para a segunda pergunta, você não pode usar lscom xargs -0porque ls não dividir a saída do bute nulo, mas com novas linhas (que são válidos em nomes de arquivos BTW)
user000001
1
@ Sinoosh: Não é o primeiro parágrafo, mas o segundo: xargs sem a -0opção sofre com a questão de espaço em branco.
user000001
1
Leia man xargs, use echopara teste, não rm. xargsnos permite exceder os limites do shell (algum buffer é limitado a 65 K, uma lista de nomes de arquivos não é).
waltinator
1
@Sinoosh: Eu não tenho uma boa referência acessível, mas você pode digitar xargs --show-limitse você vai ver o limite que está definido no seu sistema,
user000001