How to Use find -exec in Linux (With Examples)

Master the find -exec command in Linux with practical examples covering batch operations, automation, and advanced use cases.

Last updatedAuthorJoshua JamesRead time8 minGuide typeLinux Commands

The hard part of find -exec is not finding files; it is making sure the action runs on the right matches, handles odd filenames, and does not touch anything destructive before you review the target list.

Use find -exec on Linux when search results should feed directly into tools such as ls, cat, cp, gzip, chmod, grep, mv, or a small shell wrapper. The key choice is between single-file execution with \;, batched execution with +, and safer review patterns such as -print or -ok before any command changes files.

Understand the find -exec Command

What find -exec Does

Plain find answers which paths match your search. The -exec action answers what to do with those paths, so the selection logic and the file operation stay in one expression. That is often easier to reason about than a pipeline when filenames contain spaces, newlines, quotes, or other characters that break careless shell loops.

Verify GNU find Is Available

Most full Linux installations already include GNU find from the findutils package. Confirm the version before relying on GNU-specific behavior such as -printf or -execdir:

find --version

Relevant output starts with:

find (GNU findutils) 4.10.0

If the shell prints find: command not found, install the findutils package for your distro family:

sudo apt install findutils        # Debian, Ubuntu, Linux Mint
sudo dnf install findutils        # Fedora, RHEL, Rocky Linux, AlmaLinux
sudo pacman -S findutils          # Arch Linux, Manjaro
sudo zypper install findutils     # openSUSE
apk add findutils                 # Alpine, run as root when you need GNU find

Minimal containers and rescue images may expose BusyBox find instead. BusyBox supports basic -exec ... {} \;, -exec ... {} +, and -ok forms, but it does not support GNU -printf and may omit -execdir.

Basic find -exec Syntax

The two core forms differ only in the command terminator:

find [path] [expression] -exec [command] {} \;
find [path] [expression] -exec [command] {} +
  • [path]: Where to start searching. Use /var/log to scan log directories, . for the current directory, or ~ for your home folder.
  • [expression]: What to search for. Examples: -name "*.txt" finds text files, -mtime +30 finds files older than 30 days, -size +100M finds files larger than 100 megabytes.
  • -exec [command]: The action to perform on each match. Use ls -lh to list details, cp to copy, gzip to compress, or any command you would normally run manually.
  • {}: Placeholder replaced by the current matched path. If you search an absolute path, {} is absolute; if you search ., it is usually relative.
  • \;: Marks the end of the -exec command. The backslash escapes the semicolon so your shell does not interpret it prematurely.
  • +: Alternative terminator that batches multiple files into a single command invocation. GNU find requires {} immediately before +, so -exec ls -lh {} + works, while -exec cp {} /backup + does not.

The GNU findutils manual for batched -exec documents the {} + form, while the single-file form remains the most portable pattern for commands that need one path at a time.

Choose find -exec, -ok, xargs, or a Shell Wrapper

Pick the form based on how the command expects filenames and how much review you want before it runs:

NeedPatternUse When
Run once per file-exec command {} \;The command modifies one file, prompts per file, or needs the filename in a specific position.
Batch many files-exec command {} +The command accepts many path arguments at the end, such as ls, grep, or chmod.
Run multiple shell commands-exec sh -c '...' _ {} \;You need shell features such as variables, command substitution, loops, or more than one command.
Prompt before each action-ok command {} \;A deletion, move, or permission change needs manual confirmation for each match.
Use parallel processingfind ... -print0 | xargs -0 -P N commandYou need xargs features such as -P for parallel jobs. Use null-delimited input with -print0 and -0.

Understanding -exec vs -execdir

GNU -execdir works like -exec but runs the command from the directory containing the matched file, not from the directory where you launched find. This matters for commands that rely on relative paths and for operations where processing each file beside its neighbors is safer.

With -exec, the {} placeholder keeps the matched path exactly as find reports it, such as /var/log/app/error.log from an absolute search. With -execdir, find changes to /var/log/app/ first, then passes ./error.log. That shorter path avoids some path-based surprises, especially when the action creates or moves files relative to the match.

Use -execdir when:

  • Moving or renaming files to locations relative to their current directory
  • Running commands that expect to operate in the same directory as the file
  • Processing untrusted filenames where path injection is a concern

List Files with find -exec ls

At its simplest, find -exec runs a command on every match. List detailed information for every PDF under your Documents directory:

find ~/Documents -name "*.pdf" -exec ls -lh {} \;

The output shows one row per PDF with the permissions, owner, size, timestamp, and path:

-rw-r--r-- 1 user user 2.4M Jan 15 10:30 /home/user/Documents/report.pdf
-rw-r--r-- 1 user user 156K Jan 12 08:15 /home/user/Documents/notes.pdf

Common find -exec Patterns by Task

Use these patterns as starting points, then adjust the path and expression to match your files:

TaskCommand PatternWhat It Does
Show file detailsfind . -name "*.conf" -exec ls -lh {} +Batches config-file matches into fewer ls calls.
Print file contentsfind . -name "*.txt" -exec cat {} \;Prints each matching text file in turn.
Back up filesfind . -name "*.jpg" -exec cp {} {}.backup \;Creates a same-directory .backup copy for each image.
Compress files safelyfind . -name "*.log" -exec gzip -k {} \;Creates .gz copies while keeping the original logs.
Change permissionsfind . -type f -name "*.sh" -exec chmod +x {} +Makes matching shell scripts executable. Pair bulk permission work with the chmod command guide when the mode is not obvious.
Search file contentsfind . -name "*.cfg" -exec grep -H "error" {} +Searches matching config files while preserving filenames in output. For pattern options, use the grep command guide.
Move beside matchfind . -type f -name "*.tmp" -execdir sh -c 'mkdir -p ./archive && mv -- "$1" ./archive/' _ {} \;Creates an archive directory next to each match, then moves the file there.
Preview deletionfind . -name "*.log" -mtime +30 -printShows the exact old logs before you replace -print with a deletion action.

Use \; when you need one command execution per file, which is safer for operations that modify files. Use + when processing many files with read-only commands like ls or grep to reduce process spawning overhead.

Deletion, moves, overwrites, and recursive permission changes can affect many files at once. Preview matches with -print, use -ok when you want per-file confirmation, and keep backups when the operation cannot be reversed.

Practical find -exec Command Examples

Back Up Files with find -exec cp

Before a batch edit, create same-directory backup copies of the files you plan to change. This pattern keeps the original filename visible and adds a .backup suffix to each copy:

find ~/Pictures -type f -name "*.jpg" -exec cp -p {} {}.backup \;

The -p option preserves file mode, ownership when possible, and timestamps. Use a separate backup directory when you do not want backup files mixed into the source tree.

Print Matching Files with find -exec cat

Use cat with -exec when the matching files are small enough to read directly in the terminal:

find ~/Documents -type f -name "*.txt" -exec cat {} \;

Typical output is the concatenated content of each matching file:

Project notes
Meeting follow-up
Release checklist

For large text files, replace cat with grep, head, or less so you do not flood the terminal.

Rename Extensions with find -exec and mv

Bulk renaming is safer when you preview the old and new names before moving anything. The shell expansion ${1%.html}.htm removes the final .html suffix and appends .htm. For broader move and rename patterns, use the mv command guide.

find ~/web -type f -name "*.html" -exec sh -c 'printf "%s -> %s\n" "$1" "${1%.html}.htm"' _ {} \;

Renaming can overwrite files when the destination already exists. The move step uses mv -n to avoid clobbering existing .htm files.

find ~/web -type f -name "*.html" -exec sh -c 'mv -n -- "$1" "${1%.html}.htm"' _ {} \;

Compress Logs with find -exec gzip

For old logs, preview the matches first, then compress them with gzip -k. The -k flag keeps the original file while creating a .gz copy:

sudo find /var/log -type f -name "*.log" -mtime +7 -print
sudo find /var/log -type f -name "*.log" -mtime +7 -exec gzip -k {} \;

The -mtime +7 test matches files whose content was last modified more than 7 days ago. Use a larger number, such as +30, when recent logs need to remain uncompressed for active troubleshooting.

Remove Empty Directories Safely with find

Empty directories are a good place to use -delete instead of -exec rmdir because GNU find handles depth-first ordering automatically. Preview the directories before deletion:

find /data -depth -type d -empty -print

-delete permanently removes matches. Check the preview output carefully before running the deletion command.

find /data -depth -type d -empty -delete

The explicit -exec version also works when you add -depth, which processes children before parents:

find /data -depth -type d -empty -exec rmdir {} \;

For more directory removal behavior, see the rmdir command guide.

Advanced find -exec Techniques

Run Multiple Commands with find -exec sh

Use sh -c when one matched file needs more than a single command. With the batched {} + form, pass matches as positional parameters and loop over them with for file do ... done:

find ~/Documents -type f -name "*.pdf" -exec sh -c '
for file do
  printf "File: %s\n" "$file"
  ls -lh -- "$file"
done
' _ {} +

The underscore becomes $0 inside the shell. Each matched path becomes $1, $2, and so on, so the loop can handle filenames with spaces without reparsing command output.

Sync Matching Files with find and rsync

When a command reads a list of files from standard input, -printf can be a better fit than -exec. This GNU find pattern sends a null-terminated PDF list to rsync while preserving paths relative to /local/docs:

find /local/docs -type f -name "*.pdf" -printf '%P\0' | rsync -av --from0 --files-from=- /local/docs/ user@example.com:/remote/docs/

-printf '%P\0' emits each path relative to the search root and separates names with null bytes. rsync --from0 --files-from=- reads that list safely, including filenames with spaces or newlines.

Date Stamp Files with basename in find -exec

basename and dirname help rebuild filenames while keeping each file in its original directory. Preview the rename plan first:

find /data/reports -type f -name "*.csv" -exec sh -c 'printf "%s -> %s\n" "$1" "$(dirname "$1")/$(date +%Y%m%d)-$(basename "$1")"' _ {} \;

Date-stamping changes filenames and can collide with an existing dated file. The move command uses mv -n so an existing destination is left untouched.

find /data/reports -type f -name "*.csv" -exec sh -c 'mv -n -- "$1" "$(dirname "$1")/$(date +%Y%m%d)-$(basename "$1")"' _ {} \;

Generate Large File Reports with find -exec

For capacity checks, batch matching files into one ls run and save the report to a file. For deeper disk usage analysis, pair this with the du command guide.

find /home -type f -size +100M -exec ls -lh {} + > /tmp/large-files-report.txt

The report keeps one row per large file. If /home contains directories you cannot read, run the search from a narrower path you own or use the permission troubleshooting pattern later.

Build Directories from File Names with find -exec

Media workflows often need a directory named after each source file. basename "$1" .mp4 strips the extension safely, even when the filename contains spaces:

find /videos -type f -name "*.mp4" -exec sh -c 'mkdir -p "/archive/$(basename "$1" .mp4)"' _ {} \;

This creates directories such as /archive/Training Clip from /videos/Training Clip.mp4. For nested directory creation options, use the mkdir command guide.

Troubleshoot Common find -exec Errors

find: command not found

A minimal image or stripped-down container may not include find. Confirm the command lookup first:

command -v find

A working install prints a path similar to this:

/usr/bin/find

If there is no output, install findutils with the package command from the availability section, then rerun find --version.

Missing Argument to -exec

If you see this error:

find: missing argument to `-exec'

-exec did not receive a valid terminator. End the action with escaped \; for one file at a time, or put {} immediately before + for batching:

find . -name "*.txt" -exec ls -la {} \;
find . -name "*.txt" -exec ls -la {} +

Single quotes around the semicolon also work: -exec ls -la {} ';'. Do not write -exec cp {} /backup +; batching only works when {} appears right before +.

Unknown Predicate --exec

If you use two dashes, GNU find treats the option as an unknown predicate:

find: unknown predicate `--exec'

Use the single-dash action name instead:

find . -type f -name "*.log" -exec ls -lh {} \;

Permission Denied Errors

When find enters directories your user cannot read, it reports permission errors:

find: '/root': Permission denied
find: '/var/lib/private': Permission denied

Search a narrower path when possible. If you only want to hide permission noise while continuing through readable paths, redirect standard error:

find / -name "*.conf" -exec ls -la {} \; 2>/dev/null

Use sudo only when you truly need to inspect protected directories.

Files with Spaces or Special Characters

Filenames containing spaces, quotes, or shell metacharacters break when a shell wrapper expands an unquoted variable. Keep the filename in a positional parameter and quote it:

# Wrong: breaks on filenames with spaces
find . -name "*.txt" -exec sh -c 'cat $1' _ {} \;

# Correct: quotes protect the filename
find . -name "*.txt" -exec sh -c 'cat "$1"' _ {} \;

The underscore before {} becomes $0 inside the subshell, so the matched filename starts at $1.

rmdir Fails on Non-Empty Directories

If directory cleanup prints this error:

rmdir: failed to remove '/path/dir': Directory not empty

The directory was not empty when rmdir ran, or a parent directory was processed before its children. Add -depth so children are handled first:

find /data -depth -type d -empty -exec rmdir {} \;

If you do not need the explicit rmdir call, find /data -depth -type d -empty -delete is shorter after you preview the matches.

-printf Not Recognized

BusyBox find does not support GNU -printf. The error begins like this:

find: unrecognized: -printf

Install GNU findutils when you need -printf, or use a simpler command when only the basename matters:

find . -name "*.pdf" -exec basename {} \;

Conclusion

find -exec is most useful when the search and the action need to stay together. Use \; for one-path operations, {} + for batched read-only or multi-argument commands, and sh -c only when shell features are needed. Preview destructive matches first, then choose -ok, backups, or no-clobber flags when mistakes would be expensive.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Verify before posting: