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 "$@" && rm -f "$@"; 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 "$@"
a b
c d
e f
$ echo a b c d e f| xargs -n 3 echo "$@"
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 "$@"; sleep 1;'
b
d
f
$ echo a b c d e f| xargs -n 3 sh -c 'echo "$@"; 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.
First argument to sh -c
or bash -c
is the name of the script i.e. $0
which is not printed when you use $@
:
Examples:
echo a b c d e f| xargs -n 3 bash -c 'echo "$0 $@"'
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 "$@"' _
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 "$@"; 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 thecommand_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 $@' a b c
command_string
is 'tar czvf arch.tar.gz $@'
,command_name
is a
,argument
is b
argument
is c
Thus, within the command string $0
will expand to a
, $1
to b
, $2
to c
, and the $@
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With