I'm trying to construct a find command to process a bunch of files in a directory using two different executables. Unfortunately, -exec on find doesn't allow to use pipe or even \| because the shell interprets that character first.

Here is specifically what I'm trying to do (which doesn't work because pipe ends the find command):

find /path/to/jpgs -type f -exec jhead -v {} | grep 123 \; -print

As this outputs a list would you not :

find /path/to/jpgs -type f -exec jhead -v {} \; | grep 123


find /path/to/jpgs -type f -print -exec jhead -v {} \; | grep 123

Put your grep on the results of the find -exec.

That doesn't work because I need the -print to work. If grep returns a success, then find prints the file name, otherwise it doesn't.
+6  A: 

Try this

find /path/to/jpgs -type f -exec sh -c 'jhead -v {} | grep 123 \; -print' \;

Alternatively you could try to embed your exec statement inside a sh script and then do:

find -exec some_script {} \;
Martín Marconcini
That works for me. Thanks.
Great to hear that. Good luck!
Martín Marconcini
@Martin: you placed the closing apostrophe at the end of "-print", when it should be at the end of "123", and then the last "\;" is not needed.
+3  A: 

With -exec you can only run a single executable with some arguments, not arbitrary shell commands. To circumvent this, you can use sh -c '<shell command>'.

Do note that the use of -exec is quite inefficient. For each file that is found, the command has to be executed again. It would be more efficient if you can avoid this. (For example, by moving the grep outside the -exec or piping the results of find to xargs as suggested by Palmin.)

Indeed that does work. Martin scooped you on the answer though.
That's ok. I do think, however, that my comment on the (in)efficiency of -exec is also worth noting.
Another way to avoid the multiple process inefficiency in the general case is to use xargs. If you happen to need separate processes, you can use the -i option. I find xargs more in keeping with the Unix model.
Jon Ericson
AOL on xargs use. mweerden, perhaps you should change your last paragraph by taking account of the xargs existence. Also note the -0 flag that exists in both `find` and `xargs`.
+2  A: 

A slightly different approach would be to use xargs:

find /path/to/jpgs -type f -print0 | xargs -0 jhead -v | grep 123

which I always found a bit easier to understand and to adapt (the -print0 and -0 arguments are necessary to cope with filenames containing blanks)

This might (not tested) be more effective than using -exec because it will pipe the list of files to xargs and xargs makes sure that the jhead commandline does not get too long.

The problem with using xargs here is that I need the name of the file that matches. This command does find the matches, but I don't know which file matched.