xargs

Table of Content

General

xargs is parto fo the findutils (at least in debian), so if you run a debian minimal and want to have it available on your system, you have to install the package findutils

The xargs command in UNIX is a command line utility for building an execution pipeline from standard input. Whilst tools like grep can accept standard input as a parameter, many other tools cannot. Using xargs allows tools like echo and rm and mkdir to accept standard input as arguments.

How to use xargs

By default xargs reads items from standard input as separated by blanks and executes a command once for each argument. In the following example standard input is piped to xargs and the mkdir command is run for each argument, creating three folders.

$ echo "one two three" | xargs mkdir
$ ls
one two three

When filenames contains spaces you need to use -d option to change delimiter

How to use xargs with find

find /tmp -mtime +14 | xargs rm

xargs VS exec

Compare run (on a vm) removing 10k files located in current directory without any sub dirs

Using finds exec

$ time find ./ -type f -exec rm {} \;
9.48s user 5.56s system 97% cpu 15.415 total

Using xargs

$ time find ./ -type f | xargs rm
find ./ -type f  0.01s user 0.01s system 88% cpu 0.029 total
xargs rm  0.03s user 0.44s system 93% cpu 0.500 tota

How to print commands that are executed

For debugging purpose, you can add the parameter -t to printout the commands which gets executed

$ find ./ -type d | xargs -t -I % sh -c 'echo %'
sh -c 'echo ./'
./
sh -c 'echo ./one'
./one
sh -c 'echo ./two'
./two
sh -c 'echo ./three'
./three

How to run multible commands with xargs

It is possible to run multiple commands with xargs by using the parameter -I. This replaces occurrences of the argument with the argument passed to xargs.

$ find ./ -type d | xargs -t -I % sh -c 'echo %; touch %/file.txt'
sh -c 'echo ./; touch .//file.txt'
./
sh -c 'echo ./one; touch ./one/file.txt'
./one
sh -c 'echo ./two; touch ./two/file.txt'
./two
sh -c 'echo ./three; touch ./three/file.txt'
./three

$ ls *
file.txt one two three

one:
file.txt

two:
file.txt

three:
file.txt