Part III · Shell and commands
28.5 xargs
alsoxargsarguments from stdinargument list too long
TL;DR
xargsturns its input into arguments for a command, many at a time.- Use
-0withfind -print0: names with spaces or newlines stay whole. -n 1runs the command once per item;-P 4runs four at a time.
find . -name '*.log' -print0 | xargs -0 gzip
xargs -n 1 -P 4 curl -sO < urls.txt
Pitfalls
- Without
-0, a file namedmy report.pdfbecomes two arguments:myandreport.pdf. - When the input is empty, GNU xargs still runs the command once. Add
-rto skip it. -I {}puts the item where you want it (xargs -I {} mv {} {}.bak), but then runs the command once per line.- To see what would run, put
echoin front of the command:⚠ xargs -0 echo rm.
Deep dive 2 questions
Why not $(…)?
⚠ rm $(find . -name '*.tmp') also splits names on spaces. And with
thousands of files, the command fails with "Argument list too long": the
kernel caps the total size of a command's arguments. xargs splits the list
into as many runs as needed, each one under the limit.
xargs or find -exec?
find -exec cmd {} + batches arguments the same way, without a pipe (see
28.1). xargs is for input from anywhere (a file, grep -l, a list of URLs)
and for running several commands at once with -P.