Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

xargs: build commands from input

By updated

Improve this page

When you need to run a command on hundreds of files found by find, process a list from a file or avoid the "argument list too long" error, xargs is the essential tool. Simple and powerful, xargs turns standard input into arguments for another command, so that commands chain together efficiently.

What you will learn

  • Turn stdin into arguments for a command
  • Limit the number of arguments with -n
  • Place the arguments with -I
  • Handle file names with spaces (-0)
  • Run commands in parallel with -P

The xargs command in the Linux ecosystem

xargs belongs to the pipeline commands of Linux. Each tool has its speciality, and xargs is the bridge between a list and a command:

CommandSpecialityWhen to use it
xargsTurn stdin into argumentsRun a command on a list
findSearch for filesFind by name, size, date
grepFilter linesSearch for patterns
parallelAdvanced parallel executionComplex jobs, remote machines
teeDuplicate a streamWrite and display at the same time
xargs -PSimple parallelismLocal jobs in parallel

When to use xargs vs find -exec?

The table compares the two ways of acting on the result of a find: the pipe to xargs or the built-in -exec action:

Situationxargsfind -exec
Performance (fewer forks)Yes, find | xargs cmdNo with \; (one fork per file), yes with {} +
Files with spacesRequires -print0 | xargs -0Handled automatically
Parallel executionYes, -P NNo
Simple syntaxYesYes
Without a pipeNoYes, -exec cmd {} \;

Frequent combinations:

Terminal window
# find + xargs: delete files (safely)
find . -name "*.tmp" -print0 | xargs -0 rm
# grep + xargs: act on the files containing a pattern
grep -rl "TODO" src/ | xargs -I {} echo "À traiter: {}"
# cat + xargs: run on a list from a file
cat urls.txt | xargs -P 4 -I {} curl -O {}
# ls + xargs: bulk rename
ls *.bak | xargs -I {} mv {} {}.old

Understand the xargs command in 2 minutes

The mental model below sums up how xargs works: a list on stdin, a split, a target command.

🧠 Mental model: How xargs works

xargs = Read stdin → Split into arguments → Run the command with those arguments

xargs reads a list on standard input, splits it on blanks or on the null character with -0, then runs the target command with those items as arguments; -n, -I, -0 and -P adjust the splitting and the parallelism.xargsSTDINf1.txt f2.txt f3.txt, from a pipeSPLITTINGon blanks, or on \0 with -0COMMANDrm f1.txt f2.txt f3.txt-n N max arguments · -I {} placeholder-0 null separator · -P N parallelism
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

Key points

  • xargs reads stdin and turns each item into an argument
  • By default, xargs uses spaces and newlines as separators
  • With no command given, xargs uses echo by default
  • -n limits the number of arguments per run
  • -I {} lets you place the argument wherever you want
  • -0 with find -print0 handles file names containing spaces

Golden rules

1
Always use -print0 / -0 with find File names can contain spaces or special characters
2
Test with echo or -p before running Avoids destructive mistakes with rm, mv, etc.

Essential vocabulary

-n N
At most N arguments per command
-I {}
Replace {} with each input line
-0
Null separator (with find -print0)
-p
Ask for confirmation before running
-t
Print the command before running it
-r
Do not run if stdin is empty
📚 Going further: 6 advanced options
-P N
Run N commands in parallel
-L N
At most N lines per command
-a file
Read from a file instead of stdin
-d delim
Use delim as the separator
--max-procs
Alias of -P
--no-run-if-empty
Alias of -r

xargs reads stdin, splits on spaces or newlines, then passes the items as arguments to the given command.

Minimal syntax

Remember the reading order: what is left of the pipe produces text, what is right of xargs receives that text as arguments. Every option goes between xargs and the target command; an option written after the target command would be passed to it as is, which causes hard-to-read errors.

Terminal window
commande_source | xargs [OPTIONS] commande_cible

The data flow

This table serves as a diagnostic grid: when a chain does not give the expected result, first identify at which step it breaks. Nine times out of ten the problem sits at step 3, the splitting of the input, and not in the target command that you spontaneously blame.

StepDescriptionExample
1. SourceGenerates a listfind . -name "*.log"
2. PipePasses to xargs|
3. xargsSplits and groupsxargs
4. TargetReceives the argumentsrm → rm f1.log f2.log f3.log

Default behaviour

Two default behaviours deserve to be known before any serious use. First, without a target command, xargs calls echo: this is what makes it an immediate preview tool. Next, xargs groups the maximum number of arguments in a single call rather than calling the command once per item; this grouping is what brings its performance gain and avoids the Argument list too long error.

Terminal window
# Without a command: xargs uses echo
echo "a b c" | xargs
# Output: a b c
# With a command: passes every argument
echo "f1.txt f2.txt" | xargs rm
# Equivalent to: rm f1.txt f2.txt

Essential options

Seven options cover almost every use. Two are safety nets to use by reflex: -0 against exotic file names and -r against running on empty input. Two serve for debugging before committing a destructive action: -t and -p. The other three drive the splitting and the parallelism.

OptionEffectExample
-n NAt most N arguments per runxargs -n 2
-I {}Use as a placeholderxargs -I {} mv {} {}.bak
-0Null separator (with find -print0)find -print0 | xargs -0
-pAsk for confirmationxargs -p rm
-tPrint the command (trace)xargs -t echo
-rDo not run if emptyxargs -r rm
-P NN processes in parallelxargs -P 4

Limit the arguments with -n

By default, xargs passes every argument at once. -n limits the number of arguments per run:

Terminal window
# Every argument
echo "1 2 3 4 5 6" | xargs echo
# Output: 1 2 3 4 5 6
# 2 arguments per run
echo "1 2 3 4 5 6" | xargs -n 2 echo
# Output:
# 1 2
# 3 4
# 5 6

Place the argument with -I

By default, xargs appends the arguments at the end. -I {} lets you place them anywhere in the command:

Terminal window
# Without -I: arguments at the end
echo "file.txt" | xargs cp /backup/
# → cp /backup/ file.txt (ERROR!)
# With -I: control over placement
echo "file.txt" | xargs -I {} cp {} /backup/{}
# → cp file.txt /backup/file.txt (correct)

The point everyone misses: -I does not split on spaces but on newlines. The GNU manual page states that -I implies -L 1, that is one input line per run, and not -n 1 (one argument per run). The difference shows immediately:

Terminal window
printf "a b\nc d\n" | xargs -I {} echo "[{}]"
# [a b]
# [c d] <- 2 runs, one per line
printf "a b\nc d\n" | xargs -n 1 echo "["
# [ a
# [ b
# [ c
# [ d <- 4 runs, one per word

It is good news: -I correctly handles a file name containing a space as long as it takes up a whole line. A corollary to know, -n and -I are mutually exclusive: combining them makes the -n ineffective, and GNU xargs only reports it when -n comes before -I, with the warning options --max-args and --replace/-I/-i are mutually exclusive.

Handle spaces with -0

File names with spaces break xargs by default, which is why the -0 option exists, paired with find -print0:

Terminal window
# WRONG: DANGER: "mon fichier.txt" becomes 2 arguments
find . -name "*.txt" | xargs rm
# rm tries to delete "mon" and "fichier.txt" separately!
# RIGHT: SAFE: null separator
find . -name "*.txt" -print0 | xargs -0 rm
# Correctly handles "mon fichier.txt"

Test before running

Golden rule: always test with echo or -p first. xargs very often feeds rm, mv or chmod, commands with no way back. The three lines below form a progression to follow in order: look, confirm, then run. Step 1 is the most useful because it reveals the actual splitting of the input, that is exactly what you do not see when the command runs directly.

Terminal window
# 1. See what would be run
find . -name "*.tmp" | xargs echo rm
# 2. Ask for confirmation
find . -name "*.tmp" | xargs -p rm
# 3. Run (if OK)
find . -name "*.tmp" -print0 | xargs -0 rm

Parallel execution with -P

-P N lets xargs run up to N simultaneous processes. The gain is real on tasks bound by input/output (download, compression) and close to zero on a task that already saturates a core. Take the number of cores returned by nproc as a starting point, then measure: beyond it, disk contention cancels the benefit.

One limit to know before launching: xargs -P does not order the outputs. The lines of the different processes arrive interleaved on the terminal, because no buffer is reserved per process. If you need readable output, redirect each run to its own file.

Second limit, the most misleading one: -P only spreads batches. Without -n or -I, xargs puts every file in a single call, and a single process runs. Measured on eight 40 MB files: xargs -0 -P 4 gzip takes 11.1 s, exactly as without -P, whereas xargs -0 -n 1 -P 4 gzip drops to 3.9 s.

Terminal window
# Download 4 URLs in parallel (-I implies one line per run)
cat urls.txt | xargs -P 4 -I {} curl -O {}
# Compress files in parallel: -n 1 creates one batch per file
find . -name "*.log" -print0 | xargs -0 -n 1 -P 4 gzip

Typical errors (and fixes)

These five symptoms cover most xargs tickets. Read the middle column before the right one: the cause is almost always a misunderstanding of how xargs split the input, not a defect of the target command. The first two rows are the only potentially destructive ones.

ErrorCauseFix
"No such file" with spacesWrong splitting-print0 | xargs -0
Command run without an argumentEmpty stdinAdd -r
"Argument list too long"Too many filesxargs splits automatically (or -n)
not replacedMissing -IAdd -I {}
Mixed output in parallelInterleaved outputsRedirect to separate files

Common usage patterns

Now that you understand the logic of xargs, here are fourteen ready-to-use patterns. Each one gives its general formula and a concrete example.

Basic transformation

Pass a list as arguments to a command. It is the basic behaviour: xargs groups everything it receives and calls the command only once, with every item as an argument.

Terminal window
echo "a b c" | xargs <commande> # formula
echo "file1.txt file2.txt" | xargs rm # example
  • commande: the command that receives the arguments

Read from a file

Process a list of files stored in a text file, one item per line.

Terminal window
cat <liste> | xargs <commande> # formula
cat fichiers.txt | xargs rm # example
  • liste: text file containing the items to process

Limit the arguments

Run the command with a maximum number of arguments per run.

Terminal window
xargs -n N <commande> # formula
echo "1 2 3 4 5 6" | xargs -n 2 echo # example
  • -n N: at most N arguments per run

Place the argument

Use the argument at a precise position of the command, with {} as the placeholder.

Terminal window
xargs -I {} <commande avec {}> # formula
ls *.txt | xargs -I {} mv {} {}.bak # example
  • -I {}: replaces {} with each input line (implies -L 1)

Null separator (spaces in names)

Safely handle file names containing spaces, with the null character.

Terminal window
find . -print0 | xargs -0 <commande> # formula
find . -name "*.txt" -print0 | xargs -0 rm # example
  • -print0: find separates the results with a null character
  • -0: xargs reads that same null separator

Interactive confirmation

Ask for a confirmation before each run. The prompt is read on the terminal, not on standard input already taken by the pipe, which explains the failed to open /dev/tty error in a non-interactive script or a scheduled task.

Terminal window
xargs -p <commande> # formula
echo "file1 file2" | xargs -p rm # example
  • -p: asks y/n before running

Verbose mode

Print each command before running it. The trace goes to stderr, so it does not pollute a redirection of standard output to a file: you can keep -t in production without altering the collected result.

Terminal window
xargs -t <commande> # formula
echo "1 2 3" | xargs -t -n 1 echo # example
  • -t: trace, prints the command on stderr

Avoid running on empty input

Run nothing if standard input is empty. Without -r, xargs calls the command at least once even without any item, which gives stray errors with rm and can be downright dangerous with a command that acts on the current directory by default.

Terminal window
xargs -r <commande> # formula
find . -name "*.xyz" | xargs -r rm # example
  • -r: no-run-if-empty

Parallel execution

Launch several instances of the command at the same time, with -P, the parallelism option.

Terminal window
xargs -P N <commande> # formula
cat urls.txt | xargs -P 4 -I {} curl -O {} # example
  • -P N: up to N processes in parallel

find + xargs + rm

Delete the files found by find. It is the most common chain of the guide, and the most destructive one: always test it by replacing rm with echo rm before running it for real.

Terminal window
find <chemin> -name "<motif>" -print0 | xargs -0 rm # formula
find /tmp -name "*.tmp" -print0 | xargs -0 rm # example
  • The -print0 / -0 pair makes the deletion safe

find + xargs + grep

Search for text in the files found. The advantage over grep -r is to filter first on criteria that grep does not know: the date, the size or the type of entry.

Terminal window
find . -name "<motif>" -print0 | xargs -0 grep "<texte>" # formula
find . -name "*.py" -print0 | xargs -0 grep "import" # example
  • xargs passes the whole list to grep in a single command

Bulk rename

Rename several files following a pattern. It is the typical case where -I is essential, since mv expects the argument in two places: the source and the destination.

Terminal window
ls <motif> | xargs -I {} mv {} <nouveau_motif> # formula
ls *.bak | xargs -I {} mv {} {}.old # example
  • -I {} lets you reuse the argument twice (source and destination)

Create an archive

Archive the files found by find into a single archive.

Terminal window
find . -name "<motif>" -print0 | xargs -0 tar -czvf <archive> # formula
find . -name "*.log" -print0 | xargs -0 tar -czvf logs.tar.gz # example
  • xargs passes every file to tar at once, as long as the list fits in a single batch. If it exceeds the size of the command line, xargs reruns tar on the next batch and overwrites the archive: only the last batch survives. On a large volume, prefer tar --null --files-from=-, which reads the list on standard input without splitting.

Bulk permission change

Apply chmod to several files. The -type f of find is not a detail: without it, chmod +x would also apply to directories, which already need the execute bit to be traversed, and you would lose track of what you actually changed.

Terminal window
find . -type f -name "<motif>" -print0 | xargs -0 chmod <mode> # formula
find . -type f -name "*.sh" -print0 | xargs -0 chmod +x # example
  • -type f restricts to regular files

Pitfalls to avoid

Eight errors come back constantly with xargs. Several are destructive: xargs often chains into rm, so the symptom can be a lost file.

File names with spaces

Spaces in a name split one file into several arguments.

Terminal window
find . -name "*.txt" | xargs rm # WRONG: breaks on "mon fichier.txt"

Symptom: No such file error or partially deleted files. Cause: xargs splits on spaces, mon fichier.txt becomes two arguments.

Terminal window
find . -name "*.txt" -print0 | xargs -0 rm # RIGHT: null separator

Running on empty input

An empty list still triggers one run of the target command.

Terminal window
find . -name "*.xyz" | xargs rm # WRONG: runs "rm" even without any file

Symptom: error message or unexpected behaviour. Cause: xargs launches the command even when the input is empty.

Terminal window
find . -name "*.xyz" | xargs -r rm # RIGHT: -r: do nothing if empty

Running without testing

A destructive command fed by xargs deserves a preview first.

Terminal window
cat liste.txt | xargs rm # WRONG: immediate, irreversible deletion

Symptom: files deleted by mistake. Cause: no check before running.

Terminal window
cat liste.txt | xargs echo rm # RIGHT: preview, then xargs -p rm

Exceeding the argument limit

The kernel caps the total size of the arguments of a process, and a shell glob can exceed it in one go.

Terminal window
rm /var/log/app/*.log # WRONG: the shell expands the pattern into a single command line

Symptom: Argument list too long error, returned by the shell before rm even starts. Cause: the kernel limits the total size of the arguments of a process (getconf ARG_MAX, 2,097,152 bytes on Debian 13). Measured on 200,000 files: ls big/*.log fails, whereas find big -type f | xargs ls runs without an error, xargs splitting the list into batches itself.

Terminal window
find /var/log/app -name "*.log" -print0 | xargs -0 rm # RIGHT: xargs splits into batches

Placeholder without -I

{} only means something to xargs once -I is declared.

Terminal window
ls *.txt | xargs mv {} backup/ # WRONG: {} taken literally

Symptom: syntax error, {} not replaced. Cause: the {} placeholder is only active if -I is declared.

Terminal window
ls *.txt | xargs -I {} mv {} backup/ # RIGHT: -I activates the placeholder

Mixed output in parallel

Parallel processes write to the same terminal without any order.

Terminal window
xargs -P 4 commande # WRONG: the outputs of the 4 processes interleave

Symptom: the lines of the different processes are mixed. Cause: no output synchronisation between parallel processes.

Terminal window
xargs -P 4 -I {} sh -c 'commande {} > {}.out' # RIGHT: one output per file

Quotes consumed by the shell

The shell removes the quotes before xargs reads anything.

Terminal window
echo "a b" "c d" | xargs -n 1 # WRONG: gives 4 arguments, not 2

Symptom: the intended grouping disappears, you get four items instead of two. Cause: contrary to what you often read, xargs honours the quotes present in its input. The culprit is the shell, which removes the quotes before echo even writes anything: xargs receives a b c d, without any grouping mark. Proof by example, if the quotes actually reach xargs, they are honoured:

Terminal window
printf '%s\n' '"a b" "c d"' | xargs -n 1 # prints 2 lines: a b, then c d

In practice you do not rely on this mechanism, because -0 and -d disable quote processing. The explicit separator remains the reliable method:

Terminal window
printf "a b\0c d" | xargs -0 -n 1 # RIGHT: null separator, no ambiguity

Pipe after -I

A pipe written after xargs belongs to the shell, not to each run.

Terminal window
ls | xargs -I {} echo {} | wc -l # WRONG: the pipe leaves the scope of xargs

Symptom: the pipe applies to the output of xargs, not to each item. Cause: the shell splits the line at the pipe before launching xargs: wc -l is not part of the repeated command, it receives the overall output.

Terminal window
ls | xargs -I {} sh -c 'echo {} | wc -c' # RIGHT: sh -c wraps the pipe

Hands-on lab

Nothing replaces practice. Create the test environment below, then go through the twelve steps. At the end, clean up with rm -rf ~/xargs-lab.

Prepare the ground

This script creates a tree in ~/xargs-lab: documents (some of them with spaces in the name), images, logs and lists to process.

Terminal window
# Create the lab
mkdir -p ~/xargs-lab/documents ~/xargs-lab/images ~/xargs-lab/logs
cd ~/xargs-lab
# Files with simple names
echo "Contenu fichier 1" > documents/rapport.txt
echo "Contenu fichier 2" > documents/notes.txt
echo "Contenu fichier 3" > documents/todo.txt
# Files with spaces in the name (problem case)
echo "Fichier avec espace" > "documents/mon rapport.txt"
echo "Autre fichier" > "documents/mes notes importantes.txt"
# Image files
touch images/photo1.jpg images/photo2.jpg images/photo3.png
touch "images/vacances été.jpg"
# Log files
for i in {1..5}; do
echo "Log entry $i - $(date)" > logs/app$i.log
done
# List of files to process
cat > fichiers.txt << 'EOF'
documents/rapport.txt
documents/notes.txt
documents/todo.txt
EOF
# File with URLs
cat > urls.txt << 'EOF'
https://example.com/page1
https://example.com/page2
https://example.com/page3
EOF
echo "Correct : Lab créé dans ~/xargs-lab"
ls -laR ~/xargs-lab

The twelve steps

Go through them in order: each step reuses what the previous one produced. The first four stay harmless, the next ones touch real lab files. After each command, compare the output you get with the explanation sentence that follows it; if they differ, it is almost always the splitting of the input that changed.

  1. Default behaviour. Observe what xargs does without a command.

    Terminal window
    echo "un deux trois" | xargs

    Without a command, xargs passes the arguments to echo, the output is un deux trois.

  2. Delete listed files (test). Preview the deletion of the files listed in fichiers.txt.

    Terminal window
    cd ~/xargs-lab && cat fichiers.txt | xargs echo rm

    echo in front of rm shows the command that would run, without deleting anything.

  3. Limit the arguments. Print the numbers 1 to 6, two per line.

    Terminal window
    echo "1 2 3 4 5 6" | xargs -n 2 echo

    -n 2 limits each echo call to 2 arguments.

  4. Place the argument. Create a .bak copy of each .txt in the documents directory.

    Terminal window
    ls ~/xargs-lab/documents/*.txt | xargs -I {} cp {} {}.bak

    -I {} replaces {} with each argument, which lets you use it twice.

  5. Interactive confirmation. Ask for a confirmation before each deletion.

    Terminal window
    echo "test1.tmp test2.tmp" | xargs -p rm

    -p prints the command and waits for y/n before running it.

  6. Show the commands run. Trace each command before it runs.

    Terminal window
    echo "1 2 3" | xargs -t -n 1 echo "Nombre:"

    -t writes the command on stderr just before launching it.

  7. Handle spaces with find -print0. List every .txt of documents, spaces included.

    Terminal window
    find ~/xargs-lab/documents -name "*.txt" -print0 | xargs -0 ls -l

    -print0 and -0 use the null character as the separator, mon rapport.txt stays a single argument.

  8. Do not run if empty. Avoid launching rm if no .xyz file exists.

    Terminal window
    find ~/xargs-lab -name "*.xyz" | xargs -r rm

    -r prevents the run when the input is empty.

  9. Parallel execution. Simulate the download of 3 URLs in parallel.

    Terminal window
    cat ~/xargs-lab/urls.txt | xargs -P 3 -I {} echo "Downloading {}"

    -P 3 launches up to 3 commands simultaneously.

  10. Combine find and xargs for grep. Search for Contenu in every .txt.

    Terminal window
    find ~/xargs-lab/documents -name "*.txt" -print0 | xargs -0 grep "Contenu"

    xargs passes the whole list of files to grep in a single invocation.

  11. Complex pipeline with sh -c. Count the lines of each log file.

    Terminal window
    ls ~/xargs-lab/logs/*.log | xargs -I {} sh -c 'echo -n "{} : "; wc -l < "{}"'

    sh -c lets you use a pipe or several commands for each item.

  12. Compress files. Create a tar.gz archive of every .txt.

    Terminal window
    find ~/xargs-lab -name "*.txt" -print0 | xargs -0 tar -czvf ~/xargs-lab/archive.tar.gz

    xargs passes every file found to tar at once.

Progressive exercises

Ten exercises to validate your mastery. They work on the ~/xargs-lab lab. Search on your own first, then unfold the solution to check yourself.

Foundation level

These four exercises cover the splitting and placement of arguments, with no risk for your files. Each one is solved in one line. If you get stuck, rerun the command with -t: the trace shows exactly what xargs built before running.

Exercise 1, basic transformation. Print fichier1 fichier2 fichier3 on a single line with xargs. Hint: echo followed by xargs without an argument.

Show the solution
Terminal window
echo "fichier1 fichier2 fichier3" | xargs

Without a command, xargs uses echo and concatenates the arguments.

Exercise 2, limit the arguments. Print the numbers 1 to 6, two per line. Hint: -n limits the number of arguments.

Show the solution
Terminal window
echo "1 2 3 4 5 6" | xargs -n 2

-n 2 runs echo with 2 arguments on each pass.

Exercise 3, place the argument. Create the files backup_1.txt, backup_2.txt, backup_3.txt. Hint: -I {} places the argument.

Show the solution
Terminal window
printf "1\n2\n3\n" | xargs -I {} touch backup_{}.txt

-I {} replaces {} with each line of input, hence the printf with newlines. The variant echo "1 2 3" | xargs -I {} touch backup_{}.txt fails: since -I splits on newlines, it creates a single file named backup_1 2 3.txt. Adding -n 1 fixes nothing: -n and -I are mutually exclusive, and xargs ignores the -n.

Exercise 4, verbose mode. Print each echo command before it runs. Hint: -t for trace.

Show the solution
Terminal window
echo "a b c" | xargs -t -n 1 echo

-t prints the command on stderr before running it.

Composition level

Now you move on to chaining several commands and to robustness. These four exercises reproduce the situations that break in production: file names with spaces, empty input, search over a computed list. The right answer always takes into account what the upstream command produces, not only what the downstream command must do.

Exercise 5, handle spaces. List the lab's .txt files, even those with spaces in the name. Hint: find -print0 + xargs -0.

Show the solution
Terminal window
find ~/xargs-lab -name "*.txt" -print0 | xargs -0 ls -l

-print0 and -0 use the null character as the separator.

Exercise 6, avoid running on empty input. Do not run rm if no .xyz file exists. Hint: -r for no-run-if-empty.

Show the solution
Terminal window
find ~/xargs-lab -name "*.xyz" | xargs -r rm

-r prevents the run when standard input is empty.

Exercise 7, search in the files found. Search for Contenu in every .txt of the lab. Hint: find + xargs + grep.

Show the solution
Terminal window
find ~/xargs-lab -name "*.txt" -print0 | xargs -0 grep "Contenu"

xargs passes every .txt file found to grep.

Exercise 8, interactive confirmation. Ask for a confirmation before deleting each file. Hint: -p for prompt, -n 1 one file at a time.

Show the solution
Terminal window
echo "file1 file2" | xargs -p -n 1 rm

-p asks for confirmation; -n 1 processes one file at a time.

Industrialisation level

The last two exercises step out of the "one command, one list" frame. They use parallelism and wrapping with sh -c, the only way to use a pipe or a redirection inside each run. Time exercise 9 with time: it is the most telling demonstration of what -P brings.

Exercise 9, parallel execution. Simulate 4 jobs in parallel (a sleep then an echo). Hint: -P for parallelism.

Show the solution
Terminal window
printf "1\n2\n3\n4" | xargs -P 4 -I {} sh -c 'sleep 1; echo "Done {}"'

-P 4 launches up to 4 processes simultaneously, the 4 finish almost at the same time.

Exercise 10, complex pipeline. For each .log file of the lab, count the lines containing Log. Hint: sh -c for pipes inside xargs.

Show the solution
Terminal window
find ~/xargs-lab -name "*.log" -print0 | xargs -0 -I {} sh -c 'echo -n "{} : "; grep -c "Log" "{}"'

sh -c allows pipes and redirections for each processed item.

Troubleshooting

When xargs misbehaves, the problem almost always comes from the splitting of the input (spaces, batches, placeholder). Here is how to diagnose it, then how to read the error messages.

Diagnostic methods

These four commands run in this order. The first three make visible what xargs actually builds; the fourth gives the system limit beyond which the kernel refuses the command line. On a recent machine, getconf ARG_MAX often returns more than two million bytes, but xargs --show-limits gives the value that really matters: the size of the buffer actually used, 131,072 bytes by default with GNU findutils 4.10, well below the allowed maximum.

Terminal window
# See what would be run, without running anything
find . -name "*.tmp" | xargs echo rm
# Print each command before running it
echo "a b c" | xargs -t -n 1 echo
# Ask for confirmation before each run
cat liste.txt | xargs -p rm
# Know the maximum argument size of the system
getconf ARG_MAX
# See the limit actually applied by xargs on this machine
xargs --show-limits < /dev/null

Frequent errors

Four messages come back over and over. What they have in common: the errors often carry the name of the target command as a prefix, which makes you believe in a problem with rm or grep. Always check the input before blaming the command, by replaying it with xargs echo in front.

Error messageProbable causeFix
Argument list too longShell pattern (rm *.log) expanded into too many argumentsGo through find … -print0 | xargs -0, which splits into batches
xargs: argument line too longA single input item exceeds the buffer sizeCheck the separator: an input without newlines is read as one block
No such file or directorySpaces or special characters in the namesUse find -print0 | xargs -0
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 optionApostrophe in a file nameUse -0 to ignore special characters

xargs cheat sheet

The two tables below gather the options and chains you will type every day, to keep at hand while writing a command.

Options

This list extends the table of the seven essential options with three entries useful every day: -L splits by input lines and not by words, -a avoids the useless cat by reading a file directly, -d changes the separator when the input is a CSV or a variable. Watch -d and -0: both disable quote and backslash processing.

OptionRoleExample
-n NAt most N arguments per runxargs -n 2
-I {}{} as a placeholderxargs -I {} mv {} {}.bak
-0Null separator (with find -print0)find . -print0 | xargs -0
-pConfirmation before runningxargs -p rm
-tPrints the command (trace)xargs -t echo
-rRun nothing if the input is emptyxargs -r rm
-P NN processes in parallelxargs -P 4
-L NAt most N lines per runxargs -L 1
-a fichierRead from a file instead of stdinxargs -a liste.txt rm
-d delimSet the separatorxargs -d ","

Common chains

Four patterns to memorise as they are. The second, find -print0 | xargs -0, is the one to write by default as soon as files are involved: it costs six more characters and removes a whole class of incidents. The third, sh -c, is the only way to use a pipe or a redirection inside each run.

ChainRoleExample
cmd | xargsTurn stdin into argumentsecho "a b" | xargs echo
find -print0 | xargs -0Safe pattern for filesfind . -name "*.txt" -print0 | xargs -0 rm
xargs -I {} sh -c '…'Complex command with pipesxargs -I {} sh -c 'cat {} | wc -l'
cmd | xargs echoTest without runningcat liste | xargs echo rm

Mastery checklist

You master xargs when you can tick each of these points, from splitting to parallelism and sh -c wrapping:

  • I can turn standard input into arguments
  • I can limit the number of arguments with -n
  • I can place the argument with -I {}
  • I can debug with -t and -p
  • I can handle names with spaces thanks to -0
  • I can avoid running on empty input with -r
  • I can combine find, xargs and grep
  • I can run in parallel with -P
  • I can wrap a pipe with sh -c

Conclusion

The xargs command is the missing link between the commands that produce lists (find, grep -l, cat) and those that expect arguments (rm, mv, cp). Its key options are -0 (safety with spaces), -I {} (placement), -n (limitation) and -P (parallelism). For more advanced needs (remote machines, complex jobs), explore parallel.

Key points

  • xargs turns standard input into arguments, grouped as much as possible in each call.
  • Without a target command, xargs calls echo: it is the immediate preview tool.
  • find -print0 | xargs -0 is the default pattern as soon as files are involved.
  • -I {} places the argument wherever you want, one input line per run, and makes -n ineffective.
  • -r avoids running the command on empty input, -p and -t serve for debugging.
  • -P N parallelises, without ordering the outputs, and only when there are several batches: add -n 1 or -I.
  • xargs splits into batches under ARG_MAX: it is the cure for Argument list too long, not its cause.

Knowledge check

Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

FAQ: frequently asked questions

The questions below cover the points that come up most often about xargs: the basic syntax, the handling of file names containing spaces, the behaviour on empty input, the argument limit and parallelism.

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn