Is there a way to logically combine two shell commands that are invoked with find - exec?

For instance to print out all the .csv files that contain the string foo together with its occurrence I would like to do:

find . -iname \*.csv -exec grep foo {} && echo {} \;

but bash complains with "missing argument to '-exec' "

  • 3
    You could use 2 -exec in sequence or use a single -exec sh -c 'grep foo "$0" && printf %s\\n "$0"' {} \;.
    – jw013
    Nov 13, 2012 at 19:03
  • This has tripped me up repeatedly: I always expect that the first argument passed to sh (in this case {}) will be $1 and $0 will be something like sh. But in fact, you are correct, the first argument shows up as $0. Having the first argument be the name of the invoking command is just a convention, that isn't automatically enforced in these cases.
    – dubiousjim
    Nov 13, 2012 at 19:38
  • Maybe should be merged with this question: unix.stackexchange.com/q/18077/4801
    – dubiousjim
    Nov 14, 2012 at 16:02

3 Answers 3


-exec is a predicate that runs a command (not a shell) and evaluates to true or false based on the outcome of the command (zero or non-zero exit status).


find . -iname '*.csv' -exec grep foo {} \; -print

would print the file path if grep finds foo in the file. Instead of -print you can use another -exec predicate or any other predicate

find . -iname '*.csv' -exec grep foo {} \; -exec echo {} \;

See also the ! and -o find operators for negation and or.

Alternatively, you can start a shell as:

find . -iname '*.csv' -exec sh -c '
   grep foo "$1" && echo "$1"' sh {} \;

Or to avoid having to start a shell for every file:

find . -iname '*.csv' -exec sh -c '
  for i do
    grep foo "$i" && echo "$i"
  done' sh {} +

The problem you're facing is that the shell first parses the command line, and sees two simple commands separated by the && operator: find . -iname \*.csv -exec grep foo {}, and echo {} \;. Quoting && (find . -iname \*.csv -exec grep foo {} '&&' echo {} \;) bypasses that, but now the command executed by find is something like grep with the arguments foo, wibble.csv, &&, echo and wibble.csv. You need to instruct find to run a shell that will interpret the && operator:

find . -iname \*.csv -exec sh -c 'grep foo "$0" && echo "$0"' {} \;

Note that the first argument after sh -c SOMECOMMAND is $0, not $1.

You can save the startup time of a shell process for every file by grouping the command invocations with -exec … +. For ease of processing, pass some dummy value as $0 so that "$@" enumerates the file names.

find . -iname \*.csv -exec sh -c 'for x in "$@"; do grep foo "$x" && echo "$x"; done' \ {} +

If the shell command is just two programs separated by &&, find can do the job by itself: write two consecutive -exec actions, and the second one will only be executed if the first one exits with the status 0.

find . -iname \*.csv -exec grep foo {} \; -exec echo {} \;

(I assume that grep and echo are just for illustration purpose, as -exec echo can be replaced by -print and the resulting output is not particularly useful anyway.)

  • 2
    I tend to avoid using "$0" for that, as it's also used by the shell to display error messages. For instance, you could see a confusing ./some-file: grep: command not found error message. -exec find sh -c '... "$1"' sh {} \; wouldn't have the issue. There's a typo (related) in your second find command. Nov 14, 2012 at 9:31

In this specific case I would do:

find . -iname \*.csv -exec grep -l foo \{\} \;

Or if you have ack:

ack -al -G '.*\.csv' foo

To answer your actual question, something like this may work:

find . -iname \*.csv -exec sh -c "grep foo {} && echo {}" \;

  • 3
    That latter find command is not-only non-portable but also very dangerous as file paths end up being evaluated as shell code. Nov 13, 2012 at 23:16
  • All the more reason to try and avoid it by using ack/grep properly :) Nov 13, 2012 at 23:48
  • 1
    jw013's alternative (given in a comment to the question) is safer in this respect. (Just noticed that Gilles' and Stephane's answers use the same technique.)
    – dubiousjim
    Nov 14, 2012 at 2:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.