When trying to delete files larger than 2MB using find with -exec, you saw this common error:
find . -size +2M -exec rm ;
find: missing argument to -exec
The key misunderstanding was about the mandatory {} placeholder. The man page mentions it in the detailed description, though not in the brief syntax summary. The {} represents each found file in the command execution.
Here are the two proper ways to use -exec:
1. Using {} with Terminator (Single File Processing)
find . -size +2M -exec rm {} \;
This processes files one at a time, executing rm separately for each file. The backslash escapes the semicolon from shell interpretation.
2. Using {} with + (Batch Processing)
find . -size +2M -exec rm {} +
This passes multiple filenames to a single rm command, which is more efficient for bulk operations. The + tells find to append as many files as possible to each command invocation.
The + variant is generally faster because:
- Creates fewer process invocations
- Reduces command overhead
- Works better for operations that accept multiple arguments
Beyond file deletion, here are other practical uses:
# Move files to another directory
find . -name "*.bak" -exec mv {} /backup/ +
# Change permissions
find /var/www -type f -exec chmod 644 {} +
# Search within files
find . -name "*.py" -exec grep -l "import pandas" {} +
Use \; | Use + |
---|---|
When commands can't handle multiple args | For batch operations (rm, chmod, etc.) |
When processing needs to be per-file | When performance matters |
For complex commands with pipes | For simple file operations |
You can combine with other find features:
# Delete files older than 30 days, printing each first
find /tmp -mtime +30 -exec echo "Removing:" {} \; -exec rm {} +
# Process files in parallel using xargs-like behavior
find . -name "*.log" -print0 | xargs -0 -P 4 gzip
When working with Unix/Linux systems, the find
command's -exec
option frequently trips up even experienced developers. Let's dissect the correct usage patterns with concrete examples.
The basic structure requires these elements:
find [path] [expression] -exec [command] {} [terminator]
Where:
{}
- Placeholder for found files (absolute requirement)- Terminator options:
\;
- Executes command per file+
- Passes multiple files in single execution
# Correct: Single execution with {} and ;
find . -name "*.tmp" -exec rm {} \;
# Correct: Batch execution with {} and +
find /var/log -size +1G -exec gzip {} +
# WRONG: Missing placeholder
find /tmp -mtime +30 -exec rm \; # Will fail
The termination choice affects execution speed:
Terminator | Command Invocations | Best For |
---|---|---|
\; | Once per file | When commands must run separately |
+ | Once per batch | Operations supporting multiple arguments |
Combining with xargs for complex pipelines:
# Find and process files through multiple commands
find ~/projects -type f -name "*.java" -print0 | xargs -0 grep -l "deprecated"
Handling spaces in filenames safely:
find . -name "* important *" -exec mv {} "$HOME/backups" \;
- Forgetting
{}
placeholder (most frequent error) - Using unescaped
;
(must be\;
) - Mixing
+
with commands that don't support multiple args - Omitting spaces around terminators