xargs
xargs turns standard input into command arguments — it’s how shell pipelines compose commands that don’t natively read stdin. Combined with find -print0 + xargs -0 it handles spaces and newlines safely; -P adds parallelism.
Basics, -0, -P, replace, find pipes
EXAMPLE
# 1) The basic idea — pipe stdin → command arguments
echo 'a b c' | xargs touch # touch a b c
ls *.tmp | xargs rm # delete .tmp files (DANGEROUS — see -0)
find . -name '*.log' | xargs cat # cat all log files (NEWLINE bug; see -0)
# By default xargs splits on whitespace AND newlines — filenames with spaces break it.
# 2) The safe pattern — null-delimited
find . -name '*.log' -print0 | xargs -0 cat
find . -name '*.log' -print0 | xargs -0 rm
# -print0 separates with NUL bytes; xargs -0 reads them. Handles ANY filename safely.
# 3) Limit arguments per command
echo 'a b c d e f' | xargs -n 2 echo
# echo a b
# echo c d
# echo e f
# Useful for batch ops:
find . -name '*.jpg' -print0 | xargs -0 -n 1 -I {} convert {} {}.webp
# 4) Replace token with -I
ls | xargs -I {} mv {} /backup/{}.bak
find . -name '*.md' -print0 | xargs -0 -I FILE wc -l FILE
# 5) Parallel execution
find . -name '*.jpg' -print0 | xargs -0 -n 1 -P 4 -I {} convert {} {}.webp
# -P 4 = 4 jobs at once; -n 1 = one filename per job.
# Great for CPU-bound batch work; check available cores with 'nproc'.
# 6) Print the commands without running
echo 'a b' | xargs -t echo
# echo a b
# a b (the actual output)
find . -name '*.tmp' -print0 | xargs -0 -t rm
# Lets you preview what xargs WOULD run.
# 7) Confirm before each run (-p)
ls *.tmp | xargs -p rm
# rm a.tmp b.tmp c.tmp ?... (type 'y' to proceed)
# 8) Empty input handling — -r / --no-run-if-empty
find . -name '*.no-match' | xargs rm # would run 'rm' with no args (sometimes errors)
find . -name '*.no-match' | xargs -r rm # skips the command entirely
# GNU xargs has -r; BSD xargs (macOS) doesn't but treats empty input safely. Install gxargs via brew.
# 9) Real-world recipes
# Find + ESLint changed files
git diff --name-only origin/main | xargs -r npx eslint
# Find + remove old log files (older than 30 days)
find /var/log -type f -mtime +30 -print0 | xargs -0 rm
# Search files for a pattern (skip binaries)
find . -type f -print0 | xargs -0 grep -lI 'TODO'
# Compress large files
find . -type f -size +10M -print0 | xargs -0 -n 1 -P 8 gzip
# Convert .jpg to .webp in parallel
find . -type f -name '*.jpg' -print0 | xargs -0 -n 1 -P 4 -I {} \\
sh -c 'convert "$1" "${1%.jpg}.webp"' _ {}
# Remove untracked files (verify with -t first)
git ls-files --others --exclude-standard -z | xargs -0 -t rm
# 10) Read from a file
xargs -a files.txt -n 1 -I {} npm publish {}
# 11) Limit max-args for command-line length
ls /usr/bin | xargs -n 100 echo 'batch:'
# 12) Substitute multiple times in one command
docker images -q | xargs -n 1 -I {} sh -c 'docker inspect --format="{}{{.Created}}" {}'
# 13) parallel as an alternative
# GNU parallel has richer parallelism + auto-quoting
ls *.jpg | parallel convert {} {.}.webp
# parallel --citation once to acknowledge
# parallel is amazing but heavier than xargs; both have their place.
# 14) Common bugs
# • Filenames with spaces blow up — ALWAYS use -print0 / -0
# • Empty input running command with no args — use -r (GNU)
# • Quoting nightmares with -I — wrap shell commands in 'sh -c ...' explicitly
# • Race conditions on parallel writes — make sure each job writes to a UNIQUE target
# • Long arg list exceeds ARG_MAX → xargs splits automatically; -n controls batch size
# • macOS xargs differs from GNU xargs — install GNU via 'brew install findutils' as gxargs
# • Forgetting that xargs INHERITS errors silently — use 'set -e' in scripts; check exit codes
# • Piping ls output is fragile — use 'find ... -print0' for safety
# • -P without -n 1 → xargs batches files per process; subtle for some commands
Why it matters
xargs turns stdin into command-line args — the bridge between find/grep/git and tools that don’t read stdin. Always pair find -print0 with xargs -0 to survive spaces, use -P N for parallel batches, preview with -t or -p, and guard against empty input with -r.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…