What is the difference between xargs with a single command and with a complex command?

34 Views Asked by At

I am contemplating about some nuances of xargs.

Reading the question: ( what is the difference between -L and -n in xargs ) I feel irritated.

When I use a multiple argument command sh -c "..." xargs does wrong (I think):

Either a bug in MacOS and FreeBSD and Linux or something I am missing here:

$ ls *.h | xargs -L 1 sh -c 'echo "$# -- $*"'
3 -- quick brown fox.h

I would have expected the same as

$ ls *.h | xargs -L 1                            
the quick brown fox.h

But it seems, the "sh -c '...'" eats one argument (`the')

Anyone knows why and how to fix ?

1

There are 1 best solutions below

1
Grobu On

Here's an excerpt of man sh (under Debian 11):

dash -c   (...) command_string [command_name [argument ...]]

-c        Read commands from the command_string operand instead of
          from the standard input.  Special parameter 0 will be set
          from the command_name operand and the positional parameters
          ($1, $2, etc.)  set from the remaining argument operands.

That means that if you execute sh -c 'echo "blah"' the quick brown fox, the first word after the command string (i.e. the) will be used to set $0 (command name), and the remaining words will be assigned to $1, $2 and $3.

Illustration:

sh -c 'echo ">>> command name is \"$0\", I have $# arguments: $*"' the quick brown fox

>>> command name is "the", I have 3 arguments: quick brown fox

So, either put a trailing command_name argument in your xargs invocation:

echo 'the quick brown fox' | xargs -L 1 sh -c 'echo "$# -- $*"' CommandName

... or use another command than sh -c.

Hope that helps.