• Uncategorized

About linux : xargs-sh–c-skipping-the-first-argument

Question Detail

I’m trying to write a script that uses find and xargs to archive old files in a large directory. Here is the line:

find /tmp/messages/ -mtime +9 -print0 | xargs -x -t -0 -n 1000 sh -c ‘tar rPf /tmp/backup.tar “[email protected]” && rm -f “[email protected]”; sleep 1 && echo Finished one loop: $(date +”%T”)’

The script mostly works but it skips the first file each time the commands run for 1000 files and I can’t seem to figure out why.

Here is another example (I tried playing around with simpler commands to see what happens:

If I just use echo and xargs, I can run one command effectively:

$ echo a b c d e f| xargs -n 2 echo “[email protected]
a b
c d
e f
$ echo a b c d e f| xargs -n 3 echo “[email protected]
a b c
d e f

On the other hand, if I want to sleep every time I print each set, I add sh -c to add a string of commands:

$ echo a b c d e f| xargs -n 2 sh -c ‘echo “[email protected]”; sleep 1;’
$ echo a b c d e f| xargs -n 3 sh -c ‘echo “[email protected]”; sleep 1;’
b c
e f

See how the first item is skipped?

Any ideas on what could be going on here?

Thanks in advance! And let me know if you need any extra info, I’d be glad to provide it.

Question Answer

First argument to sh -c or bash -c is the name of the script i.e. $0 which is not printed when you use [email protected]:


echo a b c d e f| xargs -n 3 bash -c ‘echo “$0 [email protected]”‘
a b c
d e f

To fix this you can pass _ as dummy name of the script and then it should work:

echo a b c d e f| xargs -n 3 bash -c ‘echo “[email protected]”‘ _
a b c
d e f

It will work fine even with your sleep example:

echo a b c d e f| xargs -n 3 bash -c ‘echo “[email protected]”; sleep 1’ _
a b c
d e f

In the Shell Command language the @ special parameter

Expands to the positional parameters, starting from one.

The sh command is invoked in the following form:

sh -c[OPTIONS] command_string [command_name [argument…]]

From the documentation for the -c option:

Read commands from the command_string operand. Set the value of special parameter 0 (see Special Parameters) from the value of the command_name operand and the positional parameters ($1, $2, and so on) in sequence from the remaining argument operands.

For example, in the following command:

sh -c ‘tar czvf arch.tar.gz [email protected]’ a b c

command_string is ‘tar czvf arch.tar.gz [email protected]’,
command_name is a,
the first argument is b
the second argument is c

Thus, within the command string $0 will expand to a, $1 to b, $2 to c, and the [email protected] special parameter will expand to b c.

So if you want to use the command_name within the command string, refer to the special parameter zero, i.e. $0.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.