Skip to content

/errors/find/missing-argument-to-exec

find: missing argument to `-exec'

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · find (GNU findutils) 4.11.0updated
tool
find
exit code
1
versions
GNU findutils 4.x
os
linux, windows

GNU find prints find: missing argument to `-exec' when the command after -exec is not terminated. find needs either \; (run the command once per file) or + (run it once with many files) to know where the command ends. The semicolon must be escaped or quoted because the shell otherwise treats it as the end of the whole find command: write find . -name '*.log' -exec rm {} \; or, faster, find . -name '*.log' -exec rm {} +.

Reproduce it

bash
touch a.log b.log
find . -name '*.log' -exec echo {} ;

Output · exit 1

find: missing argument to `-exec'

The shell removed the ;, so find received -exec echo {} with nothing to close it. A {} that is not directly before + fails the same way:

bash
mkdir dest && touch a.log
find . -maxdepth 1 -name '*.log' -exec cp {} dest/ +

Output · exit 1

find: missing argument to `-exec'

Fix

bash
touch a.log b.log
echo '--- one command per file'
find . -name '*.log' -exec echo file: {} \; | sort
echo '--- one command for all files'
find . -name '*.log' -exec echo files: {} +

Output

--- one command per file
file: ./a.log
file: ./b.log
--- one command for all files
files: ./a.log ./b.log

With +, find appends as many paths as fit on one command line, which is much faster for thousands of files. Order of the paths depends on the directory, so the block sorts the first output.

{} in the middle of the command

When the file name must not be last (copying into a directory), use an option that takes the target first, or a small shell:

bash
mkdir dest && touch a.log b.log
find . -maxdepth 1 -name '*.log' -exec cp -t dest {} +
find . -maxdepth 1 -name '*.log' -exec sh -c 'for f; do cp "$f" "dest/$f.bak"; done' sh {} +
ls dest

Output

a.log
a.log.bak
b.log
b.log.bak

cp -t is GNU-only; the sh -c form works with any find. The extra sh fills $0, so the file names arrive in $@.

Other ways to lose the terminator

Gluing the semicolon to the braces does not work either: {}\; reaches find as the single word {};, which is not a terminator.

bash
touch a.log
find . -name '*.log' -exec echo {}\;

Output · exit 1

find: missing argument to `-exec'

The same happens when the find command is built inside a string, for example in ssh host "...", sh -c "..." or a Makefile recipe: each layer of quoting may strip one backslash. Switch to +, which needs no escaping at all, or check the arguments that finally reach find with set -x.

How to recognise the cause

What you typedWhy find complains
-exec rm {} ;The shell used ; as a command separator, so find never saw it
-exec rm {}\;No space before the backslash; find sees {};
-exec rm {} \ ;The backslash escapes the space, not the semicolon
-exec cp {} dest/ +With +, {} must come immediately before it
-exec rm {}The terminator was forgotten entirely

What the error does not mean

The message is about the syntax of the expression, so find exits with status 1 before it visits any file: nothing was deleted, copied or changed. Once the command is terminated correctly, failures of the command itself are different: with \; the command's exit status only acts as a true or false test and find itself still exits 0, while with + a failing command makes find exit non-zero.

Prevent it

Prefer -exec cmd {} + whenever the command accepts many paths: it is faster and has no backslash to forget. For deletions, GNU find's -delete action needs no -exec at all. Test a new expression with -exec echo {} + or -print before replacing echo with a command that changes files.

FormMeaning
-exec cmd {} \;Run cmd once per file
-exec cmd {} ';'Same, with the semicolon quoted instead of escaped
-exec cmd {} +Run cmd with many files at once; {} must be last
-execdir cmd {} \;Run cmd from the directory containing the file
-ok cmd {} \;Ask for confirmation before each command

FAQ

Should I use \; or + at the end of -exec?

Use + when the command accepts several file names, because find then runs it a few times instead of once per file. Use \; when the command takes exactly one file or {} must appear more than once.

Is -exec cmd {} + the same as piping to xargs?

It is similar: both batch file names into as few commands as possible. -exec ... + handles names with spaces and newlines safely, which with xargs needs find -print0 | xargs -0.

Does macOS find print the same message?

No. BSD find on macOS reports the same mistake with a different text, but the fix is identical: terminate the command with an escaped semicolon or with {} +.

Sources