find -exec
One very useful command for locating files and performing operations on them is find with the -exec option.
find [path] [arguments] -exec [command] {} \;
The part that’s tricky to remember is the escaped semicolon at the end.
Per-file vs batch mode
The \; terminator runs the command once per file found:
find . -name "*.log" -exec rm {} \;
# Equivalent to: rm file1.log; rm file2.log; rm file3.log
The + terminator batches files into fewer command invocations, which is faster:
find . -name "*.log" -exec rm {} +
# Equivalent to: rm file1.log file2.log file3.log
Use + when possible. Use \; when the command only accepts one argument or when you need per-file control.
Useful examples
Fix directory permissions without affecting files (the reason I wrote this post):
find /path -type d -exec chmod g+x {} +
Using chmod -R g+x would make regular files executable, which is rarely what you want.
Delete files older than 30 days:
find /tmp -type f -mtime +30 -exec rm {} +
Find and grep (when you need more control than grep -r):
find . -name "*.md" -exec grep -l "TODO" {} +
execdir
The -execdir variant runs the command from the directory containing the matched file, which is safer when filenames might contain special characters:
find . -name "*.bak" -execdir rm {} +