find: missing argument to -exec

I figured it out now. When you need to run two commands in exec in a find you need to actually have two separate execs. This finally worked for me.

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;

Try putting a space before each \;


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

Doesn't Work:

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

You have to put a space between {} and \;

So the command will be like:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {} \;

A -exec command must be terminated with a ; (so you usually need to type \; or ';' to avoid interpretion by the shell) or a +. The difference is that with ;, the command is called once per file, with +, it is called just as few times as possible (usually once, but there is a maximum length for a command line, so it might be split up) with all filenames. See this example:

$ cat /tmp/echoargs
echo $1 - $2 - $3
$ find /tmp/foo -exec /tmp/echoargs {} \;
/tmp/foo - -
/tmp/foo/one - -
/tmp/foo/two - -
$ find /tmp/foo -exec /tmp/echoargs {} +
/tmp/foo - /tmp/foo/one - /tmp/foo/two

Your command has two errors:

First, you use {};, but the ; must be a parameter of its own.

Second, the command ends at the &&. You specified “run find, and if that was successful, remove the file named {};.“. If you want to use shell stuff in the -exec command, you need to explicitly run it in a shell, such as -exec sh -c 'ffmpeg ... && rm'.

However you should not add the {} inside the bash command, it will produce problems when there are special characters. Instead, you can pass additional parameters to the shell after -c command_string (see man sh):

$ ls
$(echo damn.)
$ find * -exec sh -c 'echo "{}"' \;
$ find * -exec sh -c 'echo "$1"' - {} \;
$(echo damn.)

You see the $ thing is evaluated by the shell in the first example. Imagine there was a file called $(rm -rf /) :-)

(Side note: The - is not needed, but the first variable after the command is assigned to the variable $0, which is a special variable normally containing the name of the program being run and setting that to a parameter is a little unclean, though it won't cause any harm here probably, so we set that to just - and start with $1.)

So your command could be something like

find -exec bash -c 'ffmpeg -i "$1" -sameq "$1".mp3 && rm "$1".mp3' - {} \;

But there is a better way. find supports and and or, so you may do stuff like find -name foo -or -name bar. But that also works with -exec, which evaluates to true if the command exits successfully, and to false if not. See this example:

$ ls
false  true
$ find * -exec {} \; -and -print

It only runs the print if the command was successfully, which it did for true but not for false.

So you can use two exec statements chained with an -and, and it will only execute the latter if the former was run successfully.