The xargs command builds command lines from standard input. It is commonly used when one command produces a list of items and another command expects those items as command-line arguments rather than as text on standard input.
This distinction is important in Unix pipelines:
Producer xargs Command
+-------------+ +------------------+ +------------------+
| writes text | --stdout--> | reads stdin | --argv-> | receives args |
| to stdout | | builds arguments | | and executes |
+-------------+ +------------------+ +------------------+
For example, rm expects filenames as arguments:
rm file1.txt file2.txt file3.txtIf a previous command prints those filenames, xargs can turn the printed values into arguments for rm:
printf '%s\n' file1.txt file2.txt file3.txt | xargs rmConceptually, xargs transforms the input into a command resembling:
rm file1.txt file2.txt file3.txtThe general form is:
command-producing-items | xargs [XARGS_OPTIONS] command [COMMAND_OPTIONS]For example:
printf '%s\n' one two three | xargs echoproduces:
one two three
Here, printf writes three items to standard output. xargs reads them and executes a command equivalent to:
echo one two threeA pipe (|) connects the standard output of one process to the standard input of another process. It does not automatically turn each line into a command-line argument.
For example:
printf '%s\n' alpha beta | catworks because cat can read data from standard input.
By contrast, commands such as rm, mkdir, and many uses of cp need pathnames supplied as arguments:
rm alpha betaThis is where xargs is useful:
printf '%s\n' alpha beta | xargs rmA useful mental model is:
pipe: stdout -> stdin
xargs: stdin -> argv
where argv is the argument list passed to a program.
| Option | Description | Example |
|---|---|---|
-n N |
Pass at most N input items to each command invocation. |
xargs -n 2 echo |
-I {} |
Replace {} in the command with one input item at a time. |
xargs -I {} mv {} backup/ |
-P N |
Run up to N command invocations in parallel. |
xargs -P 4 -n 1 gzip |
-0 |
Read NUL-separated input instead of whitespace-separated input. | `find . -print0 |
-t |
Print each generated command before executing it. | xargs -t echo |
-r |
On GNU xargs, do not run the command when input is empty. |
xargs -r rm -- |
The -r option is provided by GNU xargs and is not specified by POSIX, so scripts intended for multiple Unix systems should not assume it is available.
By default, xargs tries to place as many input items as practical into each command invocation, up to system command-line size limits.
Suppose the input is:
printf '%s\n' one two three fourUsing -n 2 runs echo with two arguments at a time:
printf '%s\n' one two three four | xargs -n 2 echoOutput:
one two
three four
This is useful when a command should process only a fixed number of arguments per invocation.
The -I option defines a replacement token. A common convention is {}:
printf '%s\n' server1 server2 server3 | xargs -I {} echo "checking {}"Output:
checking server1
checking server2
checking server3
Each input item causes a separate command invocation.
Another example copies files into a backup directory:
printf '%s\n' config.ini app.conf | xargs -I {} cp -- {} backup/The generated commands are conceptually:
cp -- config.ini backup/
cp -- app.conf backup/For simple commands where arguments can appear at the end, -I is often unnecessary. For example:
printf '%s\n' file1 file2 | xargs rm --is simpler than:
printf '%s\n' file1 file2 | xargs -I {} rm -- {}The -P option allows multiple command invocations to run concurrently:
printf '%s\n' archive1 archive2 archive3 archive4 | xargs -n 1 -P 4 gzipIn this example:
-n 1gives one archive name to eachgzipinvocation.-P 4permits up to fourgzipprocesses to run at the same time.
Parallel execution can reduce processing time for independent CPU-bound or I/O-bound tasks, but it should not be used when commands depend on running in a specific order or modify the same resource.
The most important safety issue with xargs is filename parsing.
By default, xargs treats blanks, tabs, newlines, quotes, and backslashes as input syntax. Therefore, this pattern is unsafe for arbitrary filenames:
find . -type f | xargs rmA pathname such as:
./old reports/report 1.txt
contains spaces and can be interpreted incorrectly.
A robust pattern is to use NUL-delimited records:
find . -type f -print0 | xargs -0 rm --Here:
find ... -print0terminates each pathname with a NUL byte.xargs -0reads NUL-separated items.- Spaces, tabs, quotes, and newlines inside filenames remain part of the filename.
This is the preferred find + xargs pattern when arbitrary pathnames are possible.
Many Unix commands use -- to mark the end of command options. Arguments appearing after it are treated as operands even if they begin with -.
Consider a file literally named:
-rf
This is dangerous:
rm -rfbecause rm interprets -rf as options.
To explicitly treat it as a filename:
rm -- -rfThe same rule applies when xargs invokes rm:
printf '%s\n' '-rf' | xargs rm --In this command, the -- belongs to rm, not to xargs. xargs constructs a command similar to:
rm -- -rfMany tools support this convention, including rm, cp, mv, grep, and others.
A common pattern is to let find select files and xargs invoke another command.
Compress all .log files:
find logs -type f -name '*.log' -print0 | xargs -0 -n 1 gzipRemove matching temporary files:
find . -type f -name '*.tmp' -print0 | xargs -0 rm --Calculate checksums in parallel:
find images -type f -print0 | xargs -0 -n 1 -P 4 sha256sumThe find command can execute commands directly, so xargs is not always necessary.
Run once per file:
find . -type f -name '*.tmp' -exec rm -- {} \;Batch many files into each invocation:
find . -type f -name '*.tmp' -exec rm -- {} +The {} + form is often a clean alternative to:
find . -type f -name '*.tmp' -print0 | xargs -0 rm --Both approaches safely handle unusual filenames.
A practical comparison is:
| Approach | Characteristics |
|---|---|
find ... -exec command {} \; |
Executes once per pathname; simple but may create many processes. |
find ... -exec command {} + |
Batches pathnames safely without requiring xargs. |
| `find ... -print0 | xargs -0 command` |
Sometimes xargs is unnecessary because the shell can already generate the argument list.
To remove entries beginning with soi in the current directory:
rm -rf -- soi*The shell expands soi* before rm runs, producing a command conceptually similar to:
rm -rf -- soi-audio soi-beards soi-maps soi-minimapA pipeline such as:
ls | grep soi | xargs rm -rf --is less robust. Parsing ls output is generally unnecessary, and unusual filenames can make text-based pipelines ambiguous. When a shell glob expresses the selection directly, prefer the glob.
Before using xargs with destructive commands, replace the destructive command with printf or echo, or use xargs -t.
For example:
find . -type f -name '*.tmp' -print0 | xargs -0 -t rm --The -t option prints commands as they are executed.
For an entirely non-destructive preview:
find . -type f -name '*.tmp' -print0 | xargs -0 -n 1 printf 'would remove: %s\n'This makes it easier to confirm the selected pathnames before deleting anything.
An important detail is what happens when the producer returns no items.
On GNU systems, xargs normally runs the command once even when there is no input. GNU xargs -r prevents this:
find . -type f -name '*.tmp' -print0 | xargs -0 -r rm --For scripts that need portability across systems where -r may not exist, find -exec ... {} + is often a convenient alternative.
find public -type f -name '*.html' -print0 | xargs -0 chmod 644find logs -type f -name '*.log' -print0 | xargs -0 grep -n -- 'ERROR'printf '%s\n' host1 host2 host3 host4 | xargs -n 1 -P 4 ping -c 1printf '%s\n' alpha beta gamma | xargs -I {} sh -c 'printf "item: %s\n" "$1"' _ {}When a shell command is needed inside xargs, pass the item as a positional parameter rather than interpolating untrusted text directly into shell code.
I. Parsing ls output
Avoid:
ls | grep '.log' | xargs rmPrefer a shell glob when possible:
rm -- *.logor use find with NUL delimiters:
find . -maxdepth 1 -type f -name '*.log' -print0 | xargs -0 rm --II. Forgetting unusual filenames
Avoid newline-delimited filename processing when filenames may contain spaces or newlines. Use -print0 together with -0.
III. Confusing pipe input with arguments
This:
printf '%s\n' file1 file2 | rmdoes not make file1 and file2 arguments to rm.
This does:
printf '%s\n' file1 file2 | xargs rm --IV. Assuming -- belongs to xargs
In:
xargs rm -rf --xargs is being asked to run the command rm -rf -- .... The -- terminates option processing for rm.
V. Using parallel execution for dependent operations
Do not use -P when one invocation must finish before the next one starts.
- Use
printfandxargsto create three directories namedalpha,beta, andgamma. - Use
xargs -n 2to print six words two at a time. Observe how many times the command runs. - Use
xargs -I {}to transform a list of usernames into messages such aschecking alice. - Create files whose names contain spaces, then compare plain
find | xargswith the safefind -print0 | xargs -0form. - Find all
.tmpfiles below a test directory and preview their deletion without deleting them. - Repeat the previous task using
find -exec ... {} +instead ofxargs. - Use
xargs -P 4to calculate checksums for several files concurrently. - Create a file whose name begins with
-and remove it safely usingrm -- filename. - Explain the difference between
command1 | command2andcommand1 | xargs command2in terms of standard input and command arguments. - For a set of files sharing a simple prefix, compare a shell glob with an
ls | grep | xargspipeline and identify which approach is simpler and safer.