xargs Command Examples

Build and Execute Commands from Standard Input

About xargs

The xargs command reads items from standard input (stdin), delimited by blanks or newlines, and executes a command using those items as arguments. It's a powerful tool for building and executing commands dynamically, especially when dealing with long lists of files or data. xargs is essential for overcoming command-line argument length limitations and for creating efficient pipelines.

Key Capabilities:

Note: xargs is part of the findutils package and is available on all Linux/Unix systems by default. It's frequently used with find, grep, and other commands that produce lists of items.

Command Syntax

xargs [OPTIONS] [COMMAND [initial-arguments]]

Common Options

Option Description
-0, --null Input items are terminated by null character instead of whitespace
-n NUM Use at most NUM arguments per command line
-I REPLACE Replace occurrences of REPLACE in initial arguments
-L NUM Use at most NUM non-blank input lines per command
-P NUM Run up to NUM processes at a time (parallel execution)
-p Prompt before running commands (interactive mode)
-t Print commands before executing them
-d DELIM Input items are delimited by specified character
--max-procs=NUM Synonym for -P (parallel processes)
--show-limits Show operating system limits on command length

Detailed Examples

Example 1: Basic Usage - Delete Multiple Files

echo "file1.txt file2.txt file3.txt" | xargs rm
The most basic xargs usage: takes input and passes it as arguments to a command. This example:
  • Reads space-separated filenames from stdin
  • Passes them as arguments to rm
  • Equivalent to: rm file1.txt file2.txt file3.txt
This is the fundamental concept: xargs converts input lines into command arguments.
Tip: Without xargs, you'd need to type each filename manually. xargs automates this process when you have many items.

Example 2: Using with find - The Classic Combination

find . -name "*.tmp" -print0 | xargs -0 rm -f
One of the most common xargs patterns - finding and processing files:
  • find . -name "*.tmp" - Find all .tmp files
  • -print0 - Separate filenames with null character (handles spaces)
  • xargs -0 - Read null-terminated input
  • rm -f - Remove files without prompting
The -print0 and -0 combination is crucial for handling filenames with spaces, newlines, or special characters.
Warning: Without -print0 and -0, filenames with spaces will be split incorrectly. Always use these options together when dealing with filenames.

Example 3: Limit Arguments Per Command

echo "1 2 3 4 5 6 7 8 9 10" | xargs -n 3 echo "Processing:"
Processing: 1 2 3 Processing: 4 5 6 Processing: 7 8 9 Processing: 10
The -n option limits how many arguments are passed per command execution:
  • -n 3 - Use maximum 3 arguments per command
  • Command runs multiple times, once per batch
  • Useful for commands that can't handle too many arguments
  • Helps avoid "Argument list too long" errors
This is essential when processing thousands of files that would exceed system limits.

Practical example - Process files in batches:

find /backup -name "*.log" | xargs -n 100 gzip
Compresses log files 100 at a time to avoid overwhelming the system.

Example 4: Replace String in Command

find . -name "*.txt" | xargs -I {} cp {} /backup/{}
The -I option allows you to specify where arguments should be placed:
  • -I {} - Use {} as placeholder for each input item
  • Allows precise placement of arguments in command
  • Can use argument multiple times in same command
  • Essential for complex commands requiring specific argument positions
In this example, each .txt file is copied to /backup maintaining the same path structure.

More replacement examples:

# Rename files with prefix ls *.jpg | xargs -I {} mv {} backup_{} # Create directory and move file into it echo "file1 file2 file3" | xargs -I {} sh -c 'mkdir -p archive && mv {} archive/' # Process with custom placeholder cat files.txt | xargs -I FILE echo "Processing: FILE"

Example 5: Parallel Execution

find . -name "*.jpg" | xargs -P 4 -I {} convert {} {}.png
The -P option enables parallel processing:
  • -P 4 - Run up to 4 processes simultaneously
  • Dramatically speeds up processing on multi-core systems
  • Perfect for CPU-intensive or I/O-bound operations
  • Use -P 0 to run as many processes as possible
This example converts JPG files to PNG using 4 parallel processes, significantly faster than sequential processing.
Performance Tip: Set -P to your number of CPU cores for CPU-bound tasks. For I/O-bound tasks, you can use higher values (2-3x your cores).

Benchmark sequential vs parallel:

# Sequential (slow) time find . -name "*.log" | xargs gzip # Parallel with 8 processes (faster) time find . -name "*.log" | xargs -P 8 gzip

Example 6: Interactive Mode with Confirmation

find . -name "*.old" | xargs -p rm
rm ./file1.old ?...y rm ./file2.old ?...n rm ./file3.old ?...y
The -p option prompts before executing each command:
  • Shows the command that would be executed
  • Waits for user confirmation (y/n)
  • Safety mechanism for potentially destructive operations
  • Useful for reviewing actions before execution
Perfect when you want to review each file before deletion or modification.
Safety Tip: Always use -p the first time you run a potentially destructive command to verify it does what you expect.

Example 7: Verbose Mode - Show Commands

echo "file1 file2 file3" | xargs -t touch
touch file1 file2 file3
The -t option prints commands to stderr before executing them:
  • Shows exactly what xargs is executing
  • Helpful for debugging and understanding behavior
  • Non-interactive (unlike -p)
  • Commands still execute automatically
Essential for troubleshooting xargs commands and verifying correct operation.

Debugging complex pipelines:

find . -name "*.log" -mtime +30 | xargs -t -I {} sh -c 'echo "Archiving: {}"; gzip {}'
Shows each command before execution, making it easy to verify the archive process.

Example 8: Process Multiple Lines Per Command

cat << EOF | xargs -L 2 echo "Pair:" apple banana cherry date elderberry fig EOF
Pair: apple banana Pair: cherry date Pair: elderberry fig
The -L option groups multiple input lines together:
  • -L 2 - Use 2 input lines per command
  • Groups related items for processing
  • Different from -n (which counts arguments, not lines)
  • Useful for processing structured data

Process pairs of related files:

# Assuming input has pairs: source_file dest_file cat file_pairs.txt | xargs -L 2 cp

Example 9: Custom Delimiter

echo "file1.txt:file2.txt:file3.txt" | xargs -d ':' rm
The -d option specifies a custom delimiter instead of whitespace:
  • -d ':' - Use colon as delimiter
  • Useful for CSV, path-style lists, or custom formats
  • Allows processing of inputs with embedded spaces
  • Common delimiters: : (colon), , (comma), ; (semicolon)

Process PATH-style variable:

echo $PATH | xargs -d ':' -n 1 ls -ld
Lists each directory in PATH separately.

Example 10: Complex Real-World Script

#!/bin/bash # Comprehensive backup script using xargs BACKUP_DIR="/backup/$(date +%Y%m%d)" SOURCE_DIR="/data" LOG_FILE="/var/log/backup.log" echo "=== Starting Backup: $(date) ===" | tee -a "$LOG_FILE" # Create backup directory mkdir -p "$BACKUP_DIR" # Find and backup modified files from last 7 days # Process in parallel with 4 workers find "$SOURCE_DIR" -type f -mtime -7 -print0 | \ xargs -0 -P 4 -I {} sh -c ' rel_path=$(realpath --relative-to="'"$SOURCE_DIR"'" "{}") dest_dir="'"$BACKUP_DIR"'/$(dirname "$rel_path")" mkdir -p "$dest_dir" cp -p "{}" "$dest_dir/" && echo "Backed up: $rel_path" ' | tee -a "$LOG_FILE" # Archive old logs (>30 days) in batches of 50 echo "Archiving old logs..." | tee -a "$LOG_FILE" find /var/log -name "*.log" -mtime +30 -print0 | \ xargs -0 -n 50 -P 2 gzip # Remove temporary files interactively echo "Checking for temporary files..." | tee -a "$LOG_FILE" find "$SOURCE_DIR" -name "*.tmp" -o -name "*.temp" | \ xargs -p rm -f # Generate file count statistics echo "=== Backup Statistics ===" | tee -a "$LOG_FILE" find "$BACKUP_DIR" -type f | wc -l | \ xargs -I {} echo "Total files backed up: {}" | tee -a "$LOG_FILE" # Calculate total size find "$BACKUP_DIR" -type f -print0 | \ xargs -0 du -ch | tail -n 1 | \ xargs -I {} echo "Total backup size: {}" | tee -a "$LOG_FILE" echo "=== Backup Complete: $(date) ===" | tee -a "$LOG_FILE"
This comprehensive script demonstrates multiple xargs techniques:
  • Null-terminated input (-0) for safe filename handling
  • Parallel processing (-P) for performance
  • Replacement strings (-I) for complex operations
  • Batch processing (-n) to limit arguments
  • Interactive confirmation (-p) for safety
  • Pipeline integration with find, du, wc
This pattern is typical in production backup systems, deployment scripts, and batch processing automation.

Common Patterns and Use Cases

Pattern 1: Batch File Operations

# Delete all .bak files find . -name "*.bak" -print0 | xargs -0 rm # Move files to different directory find . -name "*.pdf" -print0 | xargs -0 -I {} mv {} /archive/ # Change permissions on multiple files find . -name "*.sh" -print0 | xargs -0 chmod +x # Change ownership find /var/www -user olduser -print0 | xargs -0 chown newuser:newgroup

Pattern 2: Text Processing

# Search pattern in multiple files find . -name "*.log" -print0 | xargs -0 grep "ERROR" # Count lines in multiple files find . -name "*.c" -print0 | xargs -0 wc -l # Replace text in multiple files find . -name "*.conf" -print0 | xargs -0 sed -i 's/old_value/new_value/g' # Check syntax of multiple files find . -name "*.py" | xargs -n 1 python -m py_compile

Pattern 3: System Administration

# Kill processes by name ps aux | grep process_name | awk '{print $2}' | xargs kill # Download multiple URLs cat urls.txt | xargs -n 1 -P 5 wget # Check disk usage of directories ls -d */ | xargs -I {} du -sh {} # Verify checksums cat checksums.md5 | xargs -n 2 sh -c 'md5sum "$1" | grep -q "$0"'

Pattern 4: Development Tasks

# Compile multiple source files find src -name "*.c" | xargs gcc -c # Format code files find . -name "*.java" | xargs -n 1 java-formatter # Run tests in parallel find tests -name "test_*.py" | xargs -P 4 -n 1 pytest # Build Docker images ls -d */ | xargs -I {} docker build -t myapp:{} {}

Understanding xargs Behavior

How xargs Handles Input

# Default: splits on whitespace and newlines echo "a b c d e f" | xargs echo # Output: a b c d e f (all on one line) # With -n 1: one argument per command echo "a b c" | xargs -n 1 echo # Output: # a # b # c # With -L 1: one line per command echo "a b c d e f" | xargs -L 1 echo # Output: # a b c # d e f

Handling Special Characters

Problem: Filenames with Spaces

# WRONG - breaks on spaces find . -name "*.txt" | xargs rm # This fails for "my file.txt" # CORRECT - use null terminator find . -name "*.txt" -print0 | xargs -0 rm # Works with any filename
Critical: Always use -print0 with find and -0 with xargs when dealing with filenames. This prevents issues with spaces, newlines, and special characters.

Quoting Issues

# Need to preserve quotes or special characters # Use shell with proper escaping find . -name "*.txt" -print0 | \ xargs -0 -I {} sh -c 'echo "Processing: {}"'

Performance Optimization

Performance Guidelines:

Comparing Performance

# Slowest: sequential execution find . -name "*.jpg" -exec convert {} {}.png \; # Faster: batched with xargs find . -name "*.jpg" | xargs -I {} convert {} {}.png # Fastest: parallel xargs find . -name "*.jpg" | xargs -P 4 -I {} convert {} {}.png # Alternative: GNU parallel (even faster for some tasks) find . -name "*.jpg" | parallel convert {} {}.png

Troubleshooting

Issue: Argument list too long

Error: bash: /bin/rm: Argument list too long

Solution: Use xargs to process in batches:
# Instead of: rm *.txt (fails with many files) find . -name "*.txt" -print0 | xargs -0 rm # Or with explicit batch size find . -name "*.txt" | xargs -n 100 rm

Issue: xargs processes empty input

Problem: xargs runs command even with no input

Solution: Use -r option (GNU xargs):
# WRONG: runs once with no arguments echo "" | xargs echo "Processing:" # Output: Processing: # CORRECT: doesn't run with empty input echo "" | xargs -r echo "Processing:" # Output: (nothing)

Issue: Command fails midway

xargs normally continues even if a command fails:
# To stop on first error, check exit status find . -name "*.txt" -print0 | xargs -0 -n 1 sh -c 'process "$1" || exit 255' sh # Or use set -e in shell find . -name "*.txt" -print0 | xargs -0 sh -c 'set -e; for f; do process "$f"; done'

xargs vs. Alternatives

Method Pros Cons
xargs Universal, efficient, handles argument limits Syntax can be tricky, limited parallelism
find -exec Simple syntax, built into find Slower (one process per file with \;)
while read loop Full shell control, easy to understand Slow, creates subshells
GNU parallel Advanced features, excellent parallelism Not always installed by default

When to Use Each

# xargs: general purpose, good performance find . -name "*.txt" | xargs grep "pattern" # find -exec: simple operations, one file at a time find . -name "*.txt" -exec cp {} /backup/ \; # find -exec with +: batch processing (like xargs) find . -name "*.txt" -exec rm {} + # while read: complex logic per item while IFS= read -r file; do # Complex multi-line processing do_something_complex "$file" done < <(find . -name "*.txt") # parallel: advanced parallel processing parallel process ::: file1 file2 file3

Security Considerations

Security Warnings:

Safe Practices

# UNSAFE: vulnerable to injection find . -name "*.txt" | xargs -I {} sh -c "cat {}" # SAFER: quote the argument find . -name "*.txt" | xargs -I {} sh -c 'cat "$1"' sh {} # SAFEST: avoid shell when possible find . -name "*.txt" -print0 | xargs -0 cat # For deletion, be specific find . -type f -name "*.tmp" -print0 | xargs -0 rm -f # Never do this without verification! # find / | xargs rm -rf # DANGEROUS!

Advanced Techniques

Technique 1: Process with Exit Status Checking

find . -name "*.txt" -print0 | \ xargs -0 -I {} sh -c 'process "{}" && echo "Success: {}" || echo "Failed: {}"'

Technique 2: Complex Multi-Step Processing

find . -name "*.log" -print0 | \ xargs -0 -P 4 -I {} sh -c ' echo "Processing: {}" gzip "{}" chown backup:backup "{}.gz" mv "{}.gz" /archive/ echo "Completed: {}" '

Technique 3: Conditional Execution

find . -name "*.txt" -print0 | \ xargs -0 -I {} sh -c ' if [ $(wc -l < "{}") -gt 100 ]; then echo "Large file: {}" split -l 100 "{}" "{}.part-" fi '

Related Commands

Quick Reference

# Basic usage command | xargs another_command # Handle filenames with spaces find . -name "*.txt" -print0 | xargs -0 rm # Limit arguments per command command | xargs -n 10 process # Replace string in command command | xargs -I {} process {} # Parallel execution (4 processes) command | xargs -P 4 process # Interactive confirmation command | xargs -p rm # Show commands before running command | xargs -t process # Multiple lines per command command | xargs -L 2 process # Custom delimiter echo "a:b:c" | xargs -d ':' process # Don't run if input is empty (GNU) command | xargs -r process