43

I've got a bunch of files that end in "-e" that I want to remove.

$ find . -name "*-e" exec rm {} \;
find: exec: unknown primary or operator

Is the regex expanding in some way that messes everything up?

freedrull
  • 2,194
  • 4
  • 21
  • 33
  • See [this question](http://stackoverflow.com/questions/706196/how-to-remove-files-starting-with-double-hyphen), though nothing special is needed since `{}` will expand to `./some/path/-e` which can not be treated as an option. – Reinstate Monica Please Jan 17 '15 at 08:44
  • 4
    I stumbled on this question as I was looking for example uses of `find` and `exec`, overlooking the fact that you were doing a `rm`! PSA: **This command will delete the contents of a directory! Use with caution if you're just hacking around.** I learned the hard way. – Eric Dec 06 '17 at 14:45
  • I was forgetting to use quotes around my `-name` argument value. The `*` was getting expanded by the shell and not by `find`. – Elijah Sink Jan 16 '23 at 20:29

4 Answers4

54

It should be:

find . -name "*-e" -exec rm '{}' \;

Or better:

find . -name "*-e" -exec rm '{}' +

As per man find:

-exec utility [argument ...] {} +
   Same as -exec, except that ``{}'' is replaced with as many pathnames as possible for 
   each invocation of utility. This behaviour is similar to that of xargs(1).
anubhava
  • 761,203
  • 64
  • 569
  • 643
14

+1 to @anubhava's answer. However, I did have to be very careful before it worked:

TLDR: the format is -exec <your-command> {} \;

Hint: use something harmless, like echo to get it working first.

find . -name "*.sh" -exec echo {} \;

./081.documentation/000.sticky.list_url_info_markdown/worklocal.sh
./081.documentation/001.fixed.p2.collab_diagrams/common.sh
./081.documentation/001.fixed.p2.collab_diagrams/worklocal.sh

Once it works you can get all fancy with extra find options as in

find . -name "*.sh" -maxdepth 3 -exec echo {} \;

Be sure to use -exec, not --exec or exec

remember that find’s options all take 1 dash. -exec is no different.

find . -name "*.sh" --exec echo {} \;

find: --exec: unknown primary or operator

find . -name "*.sh" exec echo {} \;

find: exec: unknown primary or operator

Notice how what comes after find: reflects what you put in? Here find has no idea what’s going on so you get a generic I don't know message.

Once you are using -exec terminate with \; - that space is critical

find . -name "*.sh" -exec echo {}\;

find: -exec: no terminating ";" or "+"
................. you want to see -exec in your error message. that part is good ✅ find knows what it is looking at so it has -exec related messages.

Finally, replace echo with your actual payload:

find . -name "*.sh" -exec reformat.py --myfancy-option-to-reformat {} \;

'{}' vs {} made no difference whatsoever.

It might, under some conditions, maybe if your paths have spaces in them so if you’re unsure put the quotes. But I couldn't trigger any errors even with spaces and with different commands (cat, ls) than echo.

find . -name "*.sh" -exec echo {} \;

./bar zoom.sh
./foo.sh
./worklocal.sh

find . -name "*.sh" -exec echo '{}' \;

./bar zoom.sh
./foo.sh
./worklocal.sh

I'm not saying the quotes are useless, I am saying they're not causing unknown primary or operator.

ending with + strips newlines between invocations:

Don't forget that space before the +.

find . -name "*.sh" -exec echo {} +

./bar zoom.sh ./foo.sh ./worklocal.sh

Yes, I dream of a more user-friendly find. But macos's Spotlight-related mdfind is, by light-years, even more unfriendly when it comes to options

Community
  • 1
  • 1
JL Peyret
  • 10,917
  • 2
  • 54
  • 73
3

use find delete args:

find ./ -name "*-e" -delete
JohnDHH
  • 409
  • 3
  • 7
-3

just use: find . "*-e" -type f exec rm '{}' + it works with Mac OSX find version

dba.in.ua
  • 593
  • 2
  • 5
  • 13