Por que xargs ignora o primeiro argumento ao passar para o subshell?

8

Procurando uma maneira de chamar mais de um comando em um liner de xargs, encontrei a recomendação no findutils de chamar o shell do xargs assim:

$ find ... | xargs sh -c 'command $@'

O engraçado é que, se eu usar xargs assim, por algum motivo, pula o primeiro argumento:

$ seq 10 | xargs bash -c 'echo $@'
2 3 4 5 6 7 8 9 10
$ seq 10 | xargs -n2 bash -c 'echo $@'
2
4
6
8
10

Há algo de errado com minha versão do shell ou do xargs? Essa documentação é imprecisa?

Usando xargs (GNU findutils) 4.4.2 e GNU bash, versão 4.3.11 (1) - liberação .

elias
fonte

Respostas:

13

A página do manual [bash] diz: " -c stringSe a opção -c estiver presente, os comandos serão lidos da string. Se houver argumentos após a string, eles serão atribuídos aos parâmetros posicionais, começando com $ 0. " - A chave é $ 0 ; significa que o nome do comando deve ser o primeiro argumento.

seq 10 | xargs sh -c 'echo $@; echo $0' sh
1 2 3 4 5 6 7 8 9 10
sh
Janis
fonte
Ah eu vejo! é por isso que os documentos colocam isso moveno final do exemplo! Eu deveria ter lido com mais cuidado ... Obrigado! =)
elias
11

Por que xargs ignora o primeiro argumento ao passar para o subshell?

Não faz. Bash atribui o primeiro argumento a $ 0:

$ seq 10 | xargs -n2 bash -c 'echo $0'
1
3
5
7
9

$@expande para $1 $2 $3.... Consequentemente, o valor de $0não está incluído no $@.

John1024
fonte
Essa explicação é muito mais clara que a da Janis, mas a resposta de Janis inclui uma boa solução para o problema.
Alexis 28/05