find exec '{}' not available after >

You could use bash -c within the find -exec command and use the positional parameter with the bash command:

find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec bash -c 'cjpeg -quality 80 "$1" > "$(dirname "$1")/optimized_$(basename "$1")"' sh {} \;

That way {} is provided with $1.

The sh before the {} tells the inner shell its "name", the string used here is used in e.g. error messages. This is discussed more in this answer on stackoverflow.


You have an answer(https://unix.stackexchange.com/a/481687/4778), but here is why.

The redirection >, and also pipes |, and $ expansion, are all done by the shell before the command is executed. Therefore stdout is redirected to optimized_{}, before find is started.


cjpeg has an option that lets you write to a named file, rather than standard output. If your version of find supports the -execdir option, you can take advantage of that to make the redirection unnecessary.

find . \( -name '*.jpg' -o -name '*.jpeg' \) \
  -execdir cjpeg -quality 80 -outfile optimized_'{}' '{}' \;

Note: this actually assumes the BSD version of find, which appears to strip the leading ./ from the file name when exanding to {}. (Or conversely, GNU find adds ./ to the name. There's no standard to say which behavior is "right".)

Tags:

Bash

Find