find -exec not working in fish

fish happens to be one of the few shells where that {} needs to be quoted.

So, with that shell, you need:

find . -type f -name '*.c' -exec chmod 644 '{}' +

When not quoted, {} expands to an empty argument, so the command becomes the same as:

find . -type f -name '*.c' -exec chmod 644 '' +

And find complains about the missing {} (or ; as + is only recognised as the -exec terminator when following {}).

With most other shells, you don't need the quotes around {}.

Your examples miss the expected trailing semicolon:

find . -type f -name "*.c" -exec chmod 644 {} \;

After revising the question, it is "fish" shell. This is a known issue which can be worked around using quoting as @rahul noticed. However, the escaping suggested does not work for my configuration: single quoting does:

find . -type f -name "*.c" -exec chmod 644 '{}' \;
find . -type f -name "*.c" -exec chmod 644 '{}' +

What does happen (if one types the characters rather than cut/paste) is that on trying to edit the command-line to escape the curly braces, fish gets confused and cannot proceed. Here's a screenshot just after inserting the backslashes (no point in trying to cut/paste that):

editing the command-line

and then pressing return:

just press return

So no, fish doesn't really work with escaped curly braces. It only pretends to do that. Continuing to press enter gives a conclusive demo:


Further reading:

  • -exec not working in find #95
  • Shell programming: How to use find in fish?

{ and } have special meanings in fish. They need to be escaped in order to work with find, for example:

find . -type f -name "*.c" -exec chmod 644 \{\} \;

Or you would have to quote {} like,

find . -type f -name "*.c" -exec chmod 644 '{}' \;