Understanding find -exec Syntax: Proper Usage of {} and + for File Operations


2 views

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