LFCS 27 ๐ง xargs โ Building Argument Lists
Some commands read their input from the standard input. The grep, the sed, the awk, and the sort are the line-oriented, and the pipe is the natural. Other commands expect the arguments on the command line. The rm, the cp, the mv, the mkdir, and the chmod take the file names as the arguments, and they do not read the standard input. The echo 'file.txt' | rm does nothing, because the rm does not read the pipe. The xargs is the bridge. It reads the items from the standard input and runs the command with the items as the arguments. The find . -name '*.log' | xargs rm finds the log files and removes them, and the xargs converts the pipe to the argument list. The xargs is the standard tool for the pipelines that end in the commands that expect the arguments, and the LFCS exam tests it as part of the “Use streams, pipes, and redirects” objective.
The xargs has the important options. The -0 reads the null-separated input, and the -print0 from the find produces it. The -n limits the number of the arguments per command, and the -I {} replaces the placeholder in the command. The -P runs the commands in the parallel, and the -t prints the command before the execution. The -r (the --no-run-if-empty) does not run the command when the input is the empty, and it is the GNU extension. The -d sets the custom delimiter, and the -L limits the lines per command.
The xargs has the specific behavior. It reads the items, the whitespace-separated by default, and it builds the argument list. The default command is the echo, and the xargs alone prints the items. The xargs runs the command once with the many arguments when possible, and the -n forces the smaller batches. The xargs is the standard input to the argument conversion, and it is the complement to the pipe.
This chapter covers three areas. First, why the xargs exists โ the argument-list problem and the pipe-to-argument bridge. Second, the syntax and the options โ the -0, the -n, the -I {}, the -P, the -t, and the -r. Third, the common patterns โ the find with the xargs, the parallel processing, the placeholder, and the safety. The chapter ends with a complete example session, a quick reference, best practices, common pitfalls, real-world examples, and diagrams showing the xargs flow.
Key point: The xargs reads the items from the standard input and runs the command with the items as the arguments. The -0 reads the null-separated input, and the find -print0 produces it. The -n limits the arguments per command, the -I {} replaces the placeholder, the -P runs in the parallel, and the -r does not run on the empty input. The xargs is the bridge between the pipe and the commands that expect the arguments.
Why xargs exists
The argument-list problem. The commands have the two kinds of the input. The filters โ the grep, the sed, the awk โ read the standard input line by line. The utilities โ the rm, the cp, the mv โ take the arguments on the command line. The echo 'file.txt' | rm does not work, because the rm ignores the standard input. The xargs reads the standard input and passes the items as the arguments: the echo 'file.txt' | xargs rm works, because the xargs converts the pipe to the rm file.txt command.
The command-line-length problem. The command line has the length limit, the ARG_MAX. The rm $(find . -name '*.log') may exceed the limit and fail with the “Argument list too long” error. The xargs splits the items into the batches and runs the command multiple times, and the limit is the respected. The -n controls the batch size.
The null-separated problem. The file names can contain the spaces, the newlines, and the quotes. The find . -name '*.log' | xargs rm splits the names on the whitespace, and the file name with the space is the broken. The -print0 from the find and the -0 from the xargs use the null character as the separator, and the file names are the preserved. The -0 is the critical for the safe.
The parallel problem. The xargs can run the commands in the parallel with the -P. The find . -name '*.jpg' | xargs -P 4 -n 1 convert runs the four conversions at once, and the wall-clock time is the reduced. The parallel is the advanced, and it is the powerful for the batch processing.
The placeholder problem. The command sometimes needs the item in the specific position, not the end. The -I {} replaces the {} in the command with the item: the find . -name '*.txt' | xargs -I {} mv {} {}.bak renames the each file. The -I also implies the -L 1, so the command runs once per item.
The trade-off. The xargs is the powerful and the subtle. The default whitespace splitting is the unsafe for the file names, and the -0 is the fix. The -I is the convenient and the slower, because it runs the command once per item. The trade-off is between the batch efficiency and the per-item control.
a. The basic xargs syntax
The xargs reads the standard input and runs the command with the items as the arguments.
echo 'file1 file2 file3' | xargs rm
# the equivalent: rm file1 file2 file3
echo 'file1 file2 file3' | xargs -n 1 ls -l
# the ls -l file1; the ls -l file2; the ls -l file3
The default command is the echo:
echo 'file1 file2' | xargs
# the file1 file2
The xargs alone prints the items, and it is the way to see the parsing.
The -n. The -n limits the arguments per command:
echo 'a b c d e f' | xargs -n 2 echo
# the echo a b; the echo c d; the echo e f
The -n 1 runs the command once per item, and the -n 2 runs it with the two items.
The -0. The -0 reads the null-separated input:
find . -name '*.log' -print0 | xargs -0 rm
The -print0 from the find produces the null-separated, and the -0 from the xargs reads it. The file names with the spaces are the preserved.
The -I {}. The -I replaces the placeholder:
find . -name '*.txt' | xargs -I {} mv {} {}.bak
# the mv file1.txt file1.txt.bak; the mv file2.txt file2.txt.bak
The {} is the placeholder, and the xargs replaces it with the item. The -I implies the -L 1, so the command runs once per item.
The -P. The -P runs the commands in the parallel:
find . -name '*.jpg' -print0 | xargs -0 -P 4 -n 1 convert
# the four convert processes at once
The -P 4 runs the four commands in the parallel, and the -n 1 runs the one item per command.
The -t. The -t prints the command before the execution:
echo 'file1 file2' | xargs -t rm
# the rm file1 file2
# the (the rm runs)
The -t is the verbose, and it shows the command.
The -r. The -r does not run the command when the input is the empty:
echo '' | xargs -r rm
# the rm is NOT run
echo '' | xargs rm
# the rm is run with the no arguments (the error)
The -r is the GNU extension, and it is the safety for the empty input.
The -d. The -d sets the custom delimiter:
echo 'a:b:c' | xargs -d: echo
# the echo a b c
The -d: uses the colon as the delimiter, and the -d '\n' uses the newline.
The -L. The -L limits the lines per command:
printf 'a\nb\nc\n' | xargs -L 1 echo
# the echo a; the echo b; the echo c
The -L 1 runs the command once per line, and the -L 2 runs it with the two lines.
b. The common patterns
The find and the xargs. The find produces the file list, and the xargs runs the command.
find . -name '*.log' -print0 | xargs -0 rm
find . -type f -size +100M -print0 | xargs -0 ls -lh
find . -name '*.tmp' -print0 | xargs -0 -r rm
The -print0 and the -0 are the safe pair, and the -r is the empty input guard.
The parallel processing. The -P runs the commands in the parallel:
find . -name '*.jpg' -print0 | xargs -0 -P 4 -n 1 convert -resize 50% {}
The -P 4 is the four parallel, and the -n 1 is the one item per command.
The placeholder. The -I {} replaces the placeholder:
find . -name '*.txt' | xargs -I {} cp {} /backup/{}
cat file.txt | xargs -I {} echo 'The line: {}'
The -I runs the command once per item, and the placeholder is the item.
The multiple arguments. The -n with the multiple items:
seq 1 10 | xargs -n 3 echo
# the echo 1 2 3; the echo 4 5 6; the echo 7 8 9; the echo 10
The sh -c. The xargs with the sh -c for the complex commands:
find . -name '*.log' -print0 | xargs -0 -I {} sh -c 'echo "Processing: $1"; gzip "$1"' _ {}
The _ is the $0, and the {} is the $1.
The dry run. The -t with the echo for the dry run:
find . -name '*.log' -print0 | xargs -0 -t echo
The -t echo prints the command without the executing.
The prompt. The -p prompts before the each command:
find . -name '*.log' -print0 | xargs -0 -p rm
The -p is the interactive, and it is the dangerous-safe.
The -a. The -a reads from the file:
xargs -a filelist.txt rm
The -a reads the items from the file instead of the standard input.
The -E. The -E sets the end-of-file string:
echo 'a b EOF c' | xargs -E EOF echo
# the echo a b
The -E EOF stops at the EOF marker.
c. The safety and the pitfalls
The whitespace splitting. The default xargs splits on the whitespace, and the file name with the space is the broken:
# โ The unsafe
find . -name '*.log' | xargs rm
# The "my file.log" is split into the "my" and the "file.log"
The -print0 and the -0 are the fix.
The empty input. The xargs with the empty input runs the command with the no arguments, and the command may do the unexpected:
# โ The dangerous
echo '' | xargs rm
# the rm with the no arguments
The -r is the guard, and it is the GNU.
The -I and the -n. The -I implies the -L 1, and it conflicts with the -n:
# โ The conflict
find . -name '*.log' | xargs -I {} -n 2 rm {}
# The -I overrides the -n
The use of the one or the other.
The command injection. The xargs with the untrusted input is the risk, because the items become the arguments:
# โ The risky
echo 'file; rm -rf /' | xargs sh -c
The sh -c with the untrusted input is the danger, and the validation is the requirement.
The -P and the output. The -P runs the commands in the parallel, and the output is the interleaved:
find . -name '*.log' -print0 | xargs -0 -P 4 grep 'error'
# The output is the interleaved from the four greps
The --output or the separate files are the fix.
The ARG_MAX. The xargs respects the ARG_MAX, and the -n controls the batch:
getconf ARG_MAX
# the 2097152 (the 2MB)
The xargs splits the long lists automatically.
The -0 with the non-null. The -0 expects the null-separated, and the newline-separated input with the -0 is the single item:
# โ The wrong
echo 'file1 file2' | xargs -0 rm
# the "file1 file2" is the single item
The -0 requires the -print0 or the null-separated input.
Complete Example Session
# ============================================
# PART 1: THE BASIC xargs
# ============================================
echo 'file1 file2 file3' | xargs rm
# the rm file1 file2 file3
echo 'a b c d e f' | xargs -n 2 echo
# the echo a b; the echo c d; the echo e f
# ============================================
# PART 2: THE NULL SEPARATOR
# ============================================
find . -name '*.log' -print0 | xargs -0 rm
# ============================================
# PART 3: THE PLACEHOLDER
# ============================================
find . -name '*.txt' | xargs -I {} mv {} {}.bak
# ============================================
# PART 4: THE PARALLEL
# ============================================
find . -name '*.jpg' -print0 | xargs -0 -P 4 -n 1 convert -resize 50%
# ============================================
# PART 5: THE VERBOSE
# ============================================
echo 'file1 file2' | xargs -t rm
# the rm file1 file2
# the (the rm runs)
# ============================================
# PART 6: THE EMPTY INPUT GUARD
# ============================================
echo '' | xargs -r rm
# the rm is NOT run
# ============================================
# PART 7: THE CUSTOM DELIMITER
# ============================================
echo 'a:b:c' | xargs -d: echo
# the echo a b c
# ============================================
# PART 8: THE LINES PER COMMAND
# ============================================
printf 'a\nb\nc\n' | xargs -L 1 echo
# the echo a; the echo b; the echo c
# ============================================
# PART 9: THE DRY RUN
# ============================================
find . -name '*.log' -print0 | xargs -0 -t echo
# the echo ./a.log ./b.log
# ============================================
# PART 10: THE LFCS PIPELINE
# ============================================
# Remove the old log files
find /var/log -name '*.log' -mtime +30 -print0 | xargs -0 rm
# The parallel compression
find /var/log -name '*.log' -print0 | xargs -0 -P 4 -n 1 gzip
# The bulk rename
find . -name '*.txt' -print0 | xargs -0 -I {} mv {} {}.bak
# The safe delete with the confirmation
find . -name '*.tmp' -print0 | xargs -0 -r -p rm
# The bulk chmod
find . -name '*.sh' -print0 | xargs -0 chmod +x
# The count the lines in the many files
find . -name '*.log' -print0 | xargs -0 wc -l
# The bulk copy
find . -name '*.conf' -print0 | xargs -0 -I {} cp {} /backup/
# The search in the many files
find . -name '*.log' -print0 | xargs -0 grep 'ERROR'
The ten parts show the basic xargs, the null separator, the placeholder, the parallel, the verbose, the empty input guard, the custom delimiter, the lines per command, the dry run, and the LFCS pipeline.
Quick Reference
The xargs Options
| The option | The purpose |
|---|---|
-0 | The null-separated |
-n N | The N arguments per command |
-I {} | The placeholder |
-P N | The N parallel |
-t | The print the command |
-p | The prompt |
-r | The no-run-if-empty |
-d X | The delimiter |
-L N | The N lines per command |
-a file | The read from the file |
-E X | The end-of-file string |
The Safe Pair
| The command | The option |
|---|---|
find | -print0 |
xargs | -0 |
xargs | -r (the GNU) |
The Common Patterns
| The pattern | The command |
|---|---|
| The delete | find ... -print0 | xargs -0 rm |
| The parallel | find ... -print0 | xargs -0 -P 4 -n 1 cmd |
| The placeholder | find ... | xargs -I {} cmd {} |
| The grep | find ... -print0 | xargs -0 grep 'x' |
| The count | find ... -print0 | xargs -0 wc -l |
The Default Behavior
| The aspect | The default |
|---|---|
| The command | echo |
| The delimiter | The whitespace |
| The arguments | The as many as possible |
| The parallel | The 1 (the sequential) |
| The empty input | The run |
The Exit Status
| The status | The meaning |
|---|---|
| 0 | The success |
| 123 | The any invocation exited 1-125 |
| 124 | The command exited 255 |
| 125 | The command killed by the signal |
| 126 | The command cannot be run |
| 127 | The command not found |
Best Practices
โ Do This:
# Use the -print0 and the -0 for the file names
find . -name '*.log' -print0 | xargs -0 rm # โ
# Use the -r for the empty input
find . -name '*.log' -print0 | xargs -0 -r rm # โ
# Use the -n for the batch
seq 1 100 | xargs -n 10 echo # โ
# Use the -I for the placeholder
find . -name '*.txt' | xargs -I {} cp {} /backup/ # โ
# Use the -P for the parallel
find . -name '*.jpg' -print0 | xargs -0 -P 4 -n 1 convert # โ
# Use the -t for the dry run
find . -name '*.log' -print0 | xargs -0 -t echo # โ
โ Don’t Do This:
# Don't use the xargs without the -0 for the spaces
find . -name '*.log' | xargs rm # the space split // โ
# Don't use the -0 without the -print0
echo 'file1 file2' | xargs -0 rm # the single item // โ
# Don't run the rm on the empty input
echo '' | xargs rm # the no args // โ
# Don't mix the -I and the -n
find . | xargs -I {} -n 2 rm {} # the -I overrides the -n // โ
# Don't use the sh -c with the untrusted input
echo 'x; rm -rf /' | xargs sh -c # the injection // โ
# Don't use the parallel with the interleaved output
find . | xargs -P 4 grep 'x' # the mixed output // โ
# Don't forget the -r in the scripts
find . -name '*.log' | xargs rm # the run on the empty // โ
(the -r is the safety)
Common Pitfalls
| The pitfall | The why | The fix |
|---|---|---|
| The space split | The default whitespace | Use the -0 with the -print0 |
| The empty input runs | The no -r | Add the -r |
The -0 with the newline | The wrong delimiter | Use the -print0 |
The -I and the -n conflict | The -I implies -L 1 | Use the one |
| The parallel output interleaved | The -P | Use the separate files |
| The command injection | The untrusted input | Validate or avoid the sh -c |
| The ARG_MAX exceeded | The long list | Use the -n |
Real-World Examples
1. The Safe Delete
find /var/log -name '*.log' -mtime +30 -print0 | xargs -0 rm
2. The Parallel Compression
find . -name '*.log' -print0 | xargs -0 -P 4 -n 1 gzip
3. The Bulk Rename
find . -name '*.txt' -print0 | xargs -0 -I {} mv {} {}.bak
4. The Bulk Chmod
find . -name '*.sh' -print0 | xargs -0 chmod +x
5. The Search in the Many Files
find . -name '*.log' -print0 | xargs -0 grep 'ERROR'
6. The Count the Lines
find . -name '*.log' -print0 | xargs -0 wc -l
7. The Bulk Copy
find . -name '*.conf' -print0 | xargs -0 -I {} cp {} /backup/
8. The Dry Run
find . -name '*.log' -print0 | xargs -0 -t echo
9. The Prompt
find . -name '*.tmp' -print0 | xargs -0 -p rm
10. The Complete
find . -name '*.log' -print0 | xargs -0 -r -P 4 -n 1 gzip
Visual
The xargs Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE xargs FLOW โ
โ โ
โ find . -name '*.log' -print0 | xargs -0 rm โ
โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โfind โ โxargs โ โrm โ โ
โ โ โ โ โ โ โ โ
โ โ the paths โโโโผโโโโบโ the items โโโโผโโโโบโ the args โ โ
โ โ (the null- โ โ (the null- โ โ โ โ
โ โ separated) โ โ separated) โ โ โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ
โ The xargs converts the stdin items to the command args. โ
โ The -0 handles the null-separated input. โ
โ The rm runs once with the many args (or the batches). โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Safe Pair
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE SAFE PAIR โ
โ โ
โ โ THE UNSAFE: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ find . -name '*.log' | xargs rm โ โ
โ โ โ โ
โ โ The "my file.log" โ the "my" and the "file.log" โ โ
โ โ The wrong files are removed. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โ
THE SAFE: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ find . -name '*.log' -print0 | xargs -0 rm โ โ
โ โ โ โ
โ โ The "my file.log" โ the "my file.log" (the one item)โ โ
โ โ The correct files are removed. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Placeholder
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE PLACEHOLDER โ
โ โ
โ find . -name '*.txt' | xargs -I {} mv {} {}.bak โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ The item: file1.txt โ โ
โ โ โ the mv file1.txt file1.txt.bak โ โ
โ โ โ โ
โ โ The item: file2.txt โ โ
โ โ โ the mv file2.txt file2.txt.bak โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The -I {} replaces the {} with the item. โ
โ The -I implies the -L 1 (the one item per command). โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Parallel
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE PARALLEL โ
โ โ
โ find . -name '*.jpg' -print0 | xargs -0 -P 4 -n 1 convert โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ the item 1 โโโบ convert (the process 1) โ โ
โ โ the item 2 โโโบ convert (the process 2) โ โ
โ โ the item 3 โโโบ convert (the process 3) โ โ
โ โ the item 4 โโโบ convert (the process 4) โ โ
โ โ โ โ
โ โ The 4 at once. The wall-clock is the reduced. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The -P 4 sets the 4 parallel. The -n 1 runs the 1 per โ
โ command. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
xargs | The stdin to the arguments |
-0 | The null-separated |
-n N | The N arguments per command |
-I {} | The placeholder |
-P N | The N parallel |
-t | The print the command |
-r | The no-run-if-empty |
-d X | The delimiter |
-L N | The N lines per command |
| The default | The echo, the whitespace |
| The safe pair | The find -print0 + the xargs -0 |
Key takeaways:
- The
xargsreads the items from the standard input and runs the command with the items as the arguments. Theecho 'file1 file2' | xargs rmconverts the pipe to therm file1 file2command. - The
-0is the critical for the safe. Thefind -print0and thexargs -0use the null separator, and the file names with the spaces are the preserved. - The
-nlimits the arguments per command. The-n 1runs the command once per item, and the-n 10runs it with the ten items. - The
-I {}replaces the placeholder. Thexargs -I {} mv {} {}.bakruns the command once per item with the{}replaced. - The
-Pruns the commands in the parallel. The-P 4runs the four commands at once, and the-n 1runs the one item per command. - The
-rdoes not run the command on the empty input. The-ris the GNU extension, and it is the safety for the scripts. - The
xargsrespects the ARG_MAX. The command line has the length limit, and thexargssplits the long lists into the batches. - The result is the argument-list building. The pipe feeds the items, and the
xargsbuilds the arguments. The result is the bridge between the filters and the utilities, which is the foundation of the shell pipelines.
Remember: The xargs reads the items from the standard input and runs the command with the items as the arguments. The -0 handles the null-separated input, and the find -print0 produces it. The -n limits the arguments, the -I {} replaces the placeholder, the -P runs in the parallel, and the -r guards the empty input. The result is the argument-list building, which is the foundation of the shell pipelines.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!