8

Looking for a way to invoke more than one command in a xargs one-liner, I found the recommendation in findutils to invoke the shell from xargs like this:

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

The funny thing is, if I use xargs like that, for some reason it skips the first argument:

$ 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

Is something wrong with my shell or xargs version? Is that documentation inaccurate?

Using xargs (GNU findutils) 4.4.2 and GNU bash, version 4.3.11(1)-release.

12

The [bash] man page says: "-c string If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0." - The key is $0; it means that the command name shall be the first argument.

seq 10 | xargs sh -c 'echo $@; echo $0' sh
1 2 3 4 5 6 7 8 9 10
sh
  • oh, I see! so that's why the docs put that move at the end in the example! I should've read more carefully... Thank you! =) – elias May 28 '15 at 3:14
10

Why does xargs skip first argument when passing to subshell?

It doesn't. Bash assigns the first argument to $0:

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

$@ expands to $1 $2 $3 .... Consequently, the value of $0 is not included in $@.

  • This explanation is much clearer than @Janis's, but Janis's answer includes a good solution to the problem. – alexis May 28 '15 at 12:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.