When working with the command line it is often useful to be able to programatically create and pass arguments. For instance, you may want to create files or folders with names from a list, or do something with each result from a program (i.e. find results). While there is almost always more than one way to do things, xargs
is a good choice, and a useful tool to have in the arsenal!
From the man page:
"xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines, and executes the command (default is /bin/echo) one or more times with any initial-arguments followed by items read from standard input."
Basically, xargs
allows you to use arbitrary data (input) as the arguments to a command. Input can be passed on the command line by piping one command into another:
(creates data) | (reads data)
1. Simple Examples:
With no arguments to xargs
, it will echo the input:
$ echo "file1 file2 file3" | xargs
file1 file2 file3
With a simple command,
xargs
will execute the command with each member of the input:
$ echo "file1 file2 file3" | xargs touch
$ ls
file1 file2 file3
With the -p switch, xargs
will prompt the user before executing each command. Type yes to confirm:
$ echo "file1 file2 file3" | xargs -p touch
thouch file1 file2 file3" ?...yes
$ ls
file1 file2 file3
2. More Useful Examples:
Perform an action on each file found. The -t
switch prints the command that will be run, and cat prints the contents of a file:
$ find -name "*cat*" | xargs -t cat
cat ./cat.txt ./cat1.txt ./cat2.txt
Lion
Panther
Jaguar
A special deliminator, something other than the default space or newline, can be specified with the -d
switch. This takes your PATH
environment variable, which is a colon separated list, and lists each directory's contents:
$ echo -n $PATH | xargs -t -d ":" ls
/bin:
...
/usr/local/bin:
...
We could use the same technique to do something with each value in a comma separated value (CSV) file:
$ cat cats.csv | xargs -t -d "," mkdir
mkdir Lion Cougar Panther Jaguar
$ ls -F
Lion/
Cougar/
Panther/
Jaguar/
However that will only work if there's only a single line in the CSV. If you have multiple lines, try wrapping xargs
in a loop!
Assuming a file where each entry is on its own line, we could use the -a
switch to read directly from the file, alleviating the need for cat
:
$ xargs -t -a cats.list mkdir
mkdir Lion Cougar Panther Jaguar
$ ls -F
Lion/
Cougar/
Panther/
Jaguar/
3. Advanced Examples:
You can also use xargs
' string replacement as a wildcard to execute multiple commands. You can make use of the sh
's -c
switch. '{}
' can be substituted for anything that doesn't exist, in its entirety, in your input:
$ cat cats.csv | xargs -d "," -I{} sh -c "echo Making directory {}; mkdir {};"
Making directory Lion
Making directory Cougar
Making directory Panther
Making directory Jaguar
$ ls -F
Cougar/
Jaguar/
Lion/
Panther/
* As noted above, this will only work if the CSV is a single line. If you had more than one line, presumably it would worth your while either to do it manually in the case of a small number of entries, or wrap xargs
in a loop.
NB. Using xargs
instead of exec
with find is often going to be more efficient, so long as the command you intend to run supports multiple inputs arguments, though it may be less flexible in some situations.