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.)
-exec
in sequence or use a single-exec sh -c 'grep foo "$0" && printf %s\\n "$0"' {} \;
. – jw013 Nov 13 '12 at 19:03sh
(in this case{}
) will be$1
and$0
will be something likesh
. 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 '12 at 19:38