Skip to main content

Execute a command with piped arguments coming from another command, a file, etc. The input is treated as a single block of text and split into separate arguments on spaces, tabs, newlines and end-of-file.

# To run a command using the input data as arguments:
<arguments_source> | xargs <command>

# To run multiple chained commands on the input data:
<arguments_source> | xargs sh -c "<command1> && <command2> | <command3>"

# To delete all files with a '.backup' extension ('-print0' uses a null character to split file names, and '-0' uses it as delimiter):
find . -name <'*.backup'> -print0 | xargs -0 rm -v

# To execute the command once for each input line, replacing any occurrences of the placeholder (here marked as '_') with the input line:
<arguments_source> | xargs -I _ <command> _ <optional_extra_arguments>

# To parallel runs of up to 'max-procs' processes at a time; the default is 1. If 'max-procs' is 0, xargs will run as many processes as possible at a time:
<arguments_source> | xargs -P <max-procs> <command>

# ---

# xargs is safer and easy to use
# `xargs` functionality can be achived using the backquote feature of shell.
# But, it offers more options. It can deal with blanks or special characters
# in file names easily. It is often used with find, grep and other commands.

# The following example will print 1 2 3 4 using xargs (echo command is default)
$ echo 1 2 3 4 | xargs echo
# OR
$ echo 1 2 3 4 | xargs

# You can force xargs to use at most max-args arguments per command line. For
# example, the following will use first two argument per command:
$ echo 1 2 3 4 | xargs -n 2

# Find all .bak files in or below the current directory and delete them.
$ find . -name "*.bak" -type f -print | xargs /bin/rm -f

# `{}` as the argument list marker

# `{}` is the default argument list marker. You need to use `{}` this with various
# command which take more than two arguments at a time. For example the `mv`
# command needs to know the file name.

# The following will find all .bak files in or below the current directory
# and move them to  `~/.old.files` directory:
$ find . -name "*.bak" -print0 | xargs -0 -I {} mv {} ~/old.files

# You can rename `{}` to something else. In the following example `{}` is renamed
# as `file`. This is more readable as compare to previous example:
$ find . -name "*.bak" -print0 | xargs -0 -I file mv file ~/old.files

# [-0]  If there are blank spaces or characters (including newlines) many commands
#       will not work. This option take cares of file names with blank space.
# [-I]  Replace occurrences of replace-str in the initial-arguments with names
#       read from standard input. Also, unquoted blanks do not terminate input
#       items; instead the separator is the newline character.

# Dealing file names with blank spaces and newline

# The following will work incorrectly if there are any filenames containing
# newlines or spaces (it will find out all .mp3 file located in current directory
# and play them using mplayer):
$ find . -iname "*.mp3" -print | xargs mplayer

# To get rid of this problem use -0 option:
$ find . -iname "*.mp3" -print0 | xargs -0 -I mp3file mplayer mp3file

# To find out all *.c file located in 100s of subdirectories and move them
# to another directory called ~/old.src, use:
$ find /path/to/dir -iname "*.c" -print0 | xargs -0 -I file mv file ~/old.src

# Avoiding errors and resource hungry problems with xargs and find combo

# To copy all media files to another location called /bakup/iscsi, you can use
#  cp as follows:
$ cp -r -v -p /share/media/mp3/ /backup/iscsi/mp3

# However, cp command may fail if an error occurs such as if the number of
# files is too large for the cp command to handle. xargs in combination with
# find can handle such operation nicely. xargs is more resource efficient
# and will not halt with an error:
$ find /share/media/mp3/ -type f -name "*.mp3" -print0 | xargs -0 -r -I file cp -v -p file --target-directory=/bakup/iscsi/mp3

# Please note that all of the above commands are tested with `GNU/xargs`
# version. BSD and UNIX xargs command may not have options such as `-r`.

# -----------------------------------------------------------------------------

# When you are trying to delete too many files using rm, you may get error
# message: `/bin/rm Argument list too long` - Linux. Use `xargs` to avoid
# this problem.
$ find ~ -name '*.log' -print0 | xargs -0 rm -f

# Get a list of all the *.conf file under /etc/. There are different ways
# to get the same result. Following example is only to demonstrate the
# use of xargs. The output of the find command in this example is
# passed to the ls –l one by one using xargs.
$ find /etc -name "*.conf" | xargs ls –l

# If you have a file with list of URLs that you would like to download,
# you can use xargs as shown below.
$ cat url-list.txt | xargs wget –c

# Find out all the jpg images and archive it.
$ find / -name *.jpg -type f -print | xargs tar -cvzf images.tar.gz

# Copy all the images to an external hard-drive.
$ ls *.jpg | xargs -n1 -i cp {} /external-hard-drive/directory

# find all file name ending with .pdf and remove them
find -name *.pdf | xargs rm -rf

# if file name contains spaces you should use this instead
find -name *.pdf | xargs -I{} rm -rf '{}'

# Will show every .pdf like:
#   &toto.pdf=
#   &titi.pdf=
# -n1 => One file by one file. ( -n2 => 2 files by 2 files )
find -name *.pdf | xargs -I{} -n1 echo '&{}='

# Resources
# - [Hack 22. Xargs Command Examples](
# - [xargs: How To Control and Use Command Line Arguments](