How do I pass combined commands to 'find -exec'?

You can use a complex shell command in the argument to exec by explicitly invoking a shell there.

find . -type f -name "*.txt" -exec sh -c 'grep FirstKeyWord "$1" | grep SecondKeyWord' -- {} \;

This executes sh with the provided command list for each file, passing the filename in $1.

EDIT: The OP points out that this works and is simpler:

find . -type f -name "*.txt" -exec sh -c 'grep FirstKeyWord {} | grep SecondKeyWord' \;

For your specific example, you can do this:

find . -type f -name "*.txt" -exec grep FirstKeyWord {} \; | grep "SecondKeyWord"

BTW, this can also be done without using a second grep. Instead, use egrep with the two alternatives of FirstKeyWord followed by SecondKeyWord or SecondKeyWord followed by FirstKeyWord:

find . -type f -name "*.txt" -exec egrep "FirstKeyWord.*SecondKeyWord|SecondKeyWord.*FirstKeyWord" {} \;

If you can make some guarantees about the resulting pathnames from the find (like no leading or internal spaces and no newlines in the pathnames), you can also do it this way:

find . -type f -name "*.txt" -print | while read filename; do grep "FirstKeyWord" "${filename}" | grep "SecondKeyWord"; done

The more general answer is "you can't" directly from find. Piping commands or using && or || is a function of the shell, not a function of executing processes.

I have used this pattern before, but it is fragile and more complex:

find . -type f -name "*.txt" -print \
    | sed -e 's;[\\$"`!];\\&;g' \
          -e 's;^.*$;grep "FirstKeyWord" "&" | grep "SecondKeyWord";' \
    | sh

Print out each filename, use sed to transform it into a shell script on the fly (being careful to escape the characters in the filename that might cause problems when enclosed in shell double-quotes), then run the result through the shell.

The other solution is to create a shell script that does your processing and call that shell script from find:

$ cat grepit.sh
#!/bin/sh
grep "FirstKeyWord" "$1" | grep "SecondKeyWord"
$ find . -type f -name "*.txt" -exec sh grepit.sh {} \;

Tags:

Bash

Find