I am new to bash and I am trying to understand the use of xargs
, which is still not clear for me. For example:
history | grep ls
Here I am searching for the command ls
in my history. In this command, I did not use xargs
and it worked fine.
find /etc - name "*.txt" | xargs ls -l
I this one, I had to use xargs
but I still can not understand the difference and I am not able to decide correctly when to use xargs
and when not.
xargs
can be used when you need to take the output from one command and use it as an argument to another. A pipe alone takes the output from one command and sends it to the input stream of another.
So in your first example, grep
can accept data from standard input, rather than as an argument and xargs
is not needed.
xargs
takes data from standard input and executes a command. By default, the data is appended to the end of the command as an argument. It can be inserted anywhere however, using a placeholder for the input. The traditional placeholder is {}
; using that, your second command might then be written as:
find /etc -name "*.txt" | xargs -I {} ls -l {}
If you have 3 text files in /etc
you'll get a full directory listing of each. Of course, you could just have easily written ls -l /etc/*.txt
and saved the trouble.
Another example lets you rename those files, and shows when the placeholder would be required. {}
has to be used twice to specify the source and destination names.
find /etc -name "*.txt" | xargs -I {} mv {} {}.bak
These are both bad examples, and will break as soon as you have a filename containing whitespace. You can work around that by telling find
to separate filenames with a null character.
find /etc -print0 -name "*.txt" | xargs -I {} -0 mv {} {}.bak
My personal opinion is that there are almost always alternatives to using xargs
(such as the -exec
argument to find
, or the process substitution operator) and you will be better served by learning those.