xargs Command Examples
The xargs command reads lines of text from the standard input or from the output of another command and turns them into commands and execute them.
You’ll often find xargs command being used with the find command. The find command gives you a list of filenames and the xargs command lets you use those filenames, one by one, as if it was input to the other command.
Since xargs works on redirection, I highly recommend brushing up your knowledge of stdin, stdout and pipe redirection in Linux.
How to use xargs command?
xargs command has the following syntax:
xargs [options] [command [initial-arguments]]
But you are probably not going to use it like that. It’s power lies in combining the output of one command to another. Let’s see it with a simple example.
In my current directory, I have some text files and the flowers.txt has the name of all these files:
abhishek@linuxhandbook:~/tutorial$ ls
flowers.txt lily.txt one_lotus.txt rose.txt three_lotus.txt two_lotus.txt
abhishek@linuxhandbook:~/tutorial$ cat flowers.txt
lily.txt
one_lotus.txt
rose.txt
three_lotus.txt
two_lotus.txt
Now my aim is that I want to see the file size of all the files mentioned in the flowers.txt. Common sense says that I could combine cat command to display all the filenames and then pipe it to the du command to check the file size.
But if I pipe it directly, it won’t give the size of each of the files mentioned in the flowers.txt file.
abhishek@linuxhandbook:~/tutorial$ du -h
52K .
abhishek@linuxhandbook:~/tutorial$ cat flowers.txt | du -h
52K .
Why? First, the du command doesn’t take standard input. Second, the output of the cat command is not individual file names. It’s a like a words separate by new line character.
The magic of xargs command is that it will take this and the text separated by blanks or new lines and convert them into individual inputs to the next command.
abhishek@linuxhandbook:~/tutorial$ cat flowers.txt | xargs du -h
4.0K lily.txt
4.0K one_lotus.txt
16K rose.txt
4.0K three_lotus.txt
16K two_lotus.txt
Think of it as equivalent to feeding those filenames to the du command:
abhishek@linuxhandbook:~/tutorial$ du -h lily.txt one_lotus.txt rose.txt three_lotus.txt two_lotus.txt
4.0K lily.txt
4.0K one_lotus.txt
16K rose.txt
4.0K three_lotus.txt
16K two_lotus.txt
You realize the power of xargs command now, don’t you?
xargs and find: made for each other
You’ll often find it being used in combination of the “find command”.
The find command searches for files and directories and returns their names. Thanks to xargs, you can use the result of the find command for specific purposes like renaming them, moving them, deleting them and whatnot.
Let’s say, you want to get all the files ending in .txt and containing the word red. You can combine find and grep commands with the help of xargs:
abhishek@linuxhandbook:~/tutorial$ find . -type f -name "*.txt" | xargs grep -l red
./three_lotus.txt
./two_lotus.txt
./rose.txt
The find exec command combination works similarly. But let's focus on the xargs command here.
Dealing with file names with spaces
If you have file with space in its name, it will cause issues. Let’s say I renamed three_lotus.txt to “three lotus.txt”. Now when it is processed via xargs, it is seen as two separate files as three and lotus.txt.
abhishek@linuxhandbook:~/tutorial$ find . -type f -name "*.txt" | xargs grep -l red
./two_lotus.txt
grep: ./three: No such file or directory
grep: lotus.txt: No such file or directory
./rose.txt
In such cases, you should use the -print0 option of the find command. It separates lines with ASCII null characters instead of newline characters. Similarly, you should also use xargs with -0 to accept the ASCII nulls.
abhishek@linuxhandbook:~/tutorial$ find . -type f -print0 -name "*.txt" | xargs -0 grep -l red
./two_lotus.txt
./three lotus.txt
./rose.txt
See what command is being executed
If you want to see what command is being executed with the help of xargs, you can use the -t option. It will print the actual command being executed.
abhishek@linuxhandbook:~/tutorial$ find . -type f -name "*.txt" | xargs -t touch
touch ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt
Force xargs to prompt for confirmation before running the command
Some situations demand to be extra careful like deleting files. It will be a good idea to see what command is going to be executed and have the option to deny the execution.
You can use the -p option of xargs to get the prompt.
abhishek@linuxhandbook:~/tutorial$ find . -type f -name "*.txt" | xargs -p rm
rm ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt ?...n
Using placeholder with xargs to get more control over it
By default, the xargs command adds the standard input as argument at the end of the command. This creates a problem when you need to use that before the last argument.
For example, if you use the move command, you need the source first and then the target. If you want to move the found files to a target directory, this command won’t work:
abhishek@linuxhandbook:~/tutorial$ find . -type f -name "*.txt" | xargs -p mv new_dir
mv new_dir ./three_lotus.txt ./two_lotus.txt ./lily.txt ./rose.txt ?...y
mv: target './rose.txt' is not a directory
This is where you can use placeholders in xargs with option -I like this:
abhishek@linuxhandbook:~/tutorial$ find . -type f -name "*.txt" | xargs -p -I {} mv {} new_dir
mv ./three_lotus.txt new_dir ?...n
mv ./two_lotus.txt new_dir ?...n
mv ./lily.txt new_dir ?...n
mv ./rose.txt new_dir ?...n
Think of it as if xargs gets all the file names from the find command and keep it in {}. Then it goes to the mv command and supplies the content of {}.
The major difference here is that instead of putting all the file names in the same command, it adds them one by one. This is why the mv command’s been called for each argument (as you can see in the above example).
Note: I used {} as placeholder. You could most other letters or characters as placeholder. {} is safe bet and easy to understand and distinguish.
Running multiple commands with xargs
You may use the placeholders to run multiple commands with xargs.
abhishek@linuxhandbook:~/tutorial$ find . -type f -name "*.txt" | xargs -I {} sh -c 'ls -l {}; du -h {}'
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./three_lotus.txt
0 ./three_lotus.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./two_lotus.txt
0 ./two_lotus.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./lily.txt
0 ./lily.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 28 17:02 ./rose.txt
0 ./rose.txt
Keep in mind that placeholder won’t extend to the next pipe redirection or other command. This is why I used sh command here.
There’s always more…
I have mainly used find with xargs command in the examples here because that’s what you’ll see the most. But that doesn’t mean xargs is restricted to be used with find command only. One such practical example of xargs command is when you want to stop all running docker containers:
docker ps -q | xargs docker stop
Like most other Linux commands, there are plenty more options with xargs as well. You can always refer to the man page of xargs command for more information.
I think the xargs command examples listed here are enough to give you a good understanding of this awesome command.
If you have any questions or suggestions, please let me know in the comment section.