Skip to content

/flags/find/find-exec-plus-vs-semicolon

find -exec {} + vs -exec {} \;: batch or one command per file

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · find (GNU findutils) 4.11.0updated
tool
find
command
find
flag
-exec command {} ; and -exec command {} +
default
no command is run; find only prints the matching paths

find . -name '*.txt' -exec wc -l {} + runs wc once with as many file names as fit on a command line; find . -name '*.txt' -exec wc -l {} \; runs wc once per file. Both replace {} with the path and both are POSIX. Use + by default: it is much faster on many files, and it works like xargs without any problem with spaces in names. Use \; when the command accepts only one file, or when {} must appear in the middle of the arguments.

The difference in one run

bash
mkdir -p proj
touch proj/a.txt proj/b.txt 'proj/my file.txt'
echo '-- one invocation per file'; find proj -name '*.txt' -exec echo run: {} \; | sort
echo '-- one batch'; find proj -name '*.txt' -exec echo run: {} + | tr ' ' '\n' | grep -c '^run:'

Output

-- one invocation per file
run: proj/a.txt
run: proj/b.txt
run: proj/my file.txt
-- one batch
1

The \; form starts echo three times; the + form starts it once with all three names. The backslash stops the shell from treating ; as the end of the shell command; ';' works too.

Exit status

bash
mkdir -p ex; touch ex/a.txt
find ex -name a.txt -exec false {} \; ; echo "with \\;  exit: $?"
find ex -name a.txt -exec false {} + ; echo "with +   exit: $?"

Output

with \;  exit: 0
with +   exit: 1

With \; the command's exit status is only used as the value of the test (true or false), so find still exits 0. With + any failing batch makes find exit non-zero when it finishes. In scripts with set -e, + is the one that reports failures.

Comparison

-exec cmd {} \;-exec cmd {} +
Invocationsone per fileone per batch (limited by ARG_MAX)
Position of {}anywhere, can repeatlast, right before +
Return value as a testtrue if cmd exits 0always true
find exit status on cmd failureunaffectednon-zero
Speed on 10,000 filesslow: 10,000 processesfast: a handful of processes

Because \; returns the command's status, it can act as a filter: find . -type f -exec grep -q TODO {} \; -print prints only the files that contain TODO.

ActionWhat it does
-execdir cmd {} ;/+Runs cmd from the directory of each match, with ./name; safer against path races (GNU and BSD)
-ok cmd {} ;Like -exec ;, but asks for confirmation before each command
-print0 | xargs -0Same batching via a pipe, plus xargs -P for parallelism

Errors and pitfalls

bash
find . -exec echo {} x +

Output · exit 1

find: missing argument to `-exec'

Anything after {} in the + form, or a missing terminator, produces missing argument to -exec. Other traps:

  • {} is not quoted by find. If the command is a shell (-exec sh -c '...' {} \;), pass the name as an argument (sh -c 'echo "$1"' sh {}) instead of pasting {} into the script, or a crafted file name can inject commands.
  • Shell features such as pipes or redirections do not work inside -exec; wrap them in sh -c.
  • The batch form never builds a command longer than the system limit, so it does not cause Argument list too long, unlike cmd $(find ...). For NUL-safe pipelines see find -print0 | xargs -0.

FAQ

Why does find say missing argument to -exec?

The command is not terminated. End it with \; or with + right after {}, and make sure the shell passes the semicolon to find (escape or quote it).

Can I put text after {} when using +?

No. With + the {} must be the last argument before the +. To move files into a directory use GNU mv -t, as in find . -name '*.log' -exec mv -t old/ {} +.

Does find stop when the command fails?

No. find continues with the next file in both forms. With \; the failure is ignored for the exit status; with + find exits non-zero at the end if any invocation failed.

Sources