I want to use a find -exec
from a bash function.
I know I need to terminate the -exec
with a {} \;
, but I can't find the proper way of doing it!
I tried :
find $SEARCHPATH -name \"${FILEPAT}.[ch]\" -exec grep --color -aHn \"$GREPPATTERN\" {} \;
find $SEARCHPATH -name \"${FILEPAT}.[ch]\" -exec grep --color -aHn \"$GREPPATTERN\" '{}' \;
find $SEARCHPATH -name \"${FILEPAT}.[ch]\" -exec grep --color -aHn \"$GREPPATTERN\" \{\} \;
find $SEARCHPATH -name \"${FILEPAT}.[ch]\" -exec grep --color -aHn \"$GREPPATTERN\" '{}' ';'
And many other, but I can't get anything to work.
Most of the time I get find: missing argument to '-exec'
And when find
accepts the syntax I get no results for simple request like:
find . -name "*.[ch]" -exec grep --color -aHn "e" {} \;
Would someone help me with this one? Thanks!
Don't escape the quotes around the arguments -- when you do that, the quotes are treated as part of the arguments, and it's e.g. looking for files with actual quotes in the filename. Use something like this:
f() {
searchpath=$1
filepat=$2
greppattern=$3
find "$searchpath" -name "$filepat.[ch]" -exec grep --color -aHn "$greppattern" {} \;
}
[EDIT] To expand my comment about the quotes being treated as part of the arguments: quotes in a command line affect how the text inside them is parsed. Double-quotes allow variable references ('$varname`) to be expanded and a few other things, but not much else. Once they've had this effect, they are removed (i.e. they are not passed on to the command itself). To see this, let's define a function that just prints its arguments, and see what it actually receives from various command lines:
$ printargs() { printf " <%s>\n" "$@"; }
$ printargs one two
<one>
<two>
$ printargs "one" "two" # The quotes will be removed before printargs sees them
<one>
<two>
$ printargs "one two" # The quotes make the two words into one argument, but again aren't passed on to printargs
<one two>
$ printargs "one" 'two' three # Single-quotes are also removed
<one>
<two>
<three>
Similar things happen with variables:
$ var="one two" # Note that the quotes are removed before the value is stored in $var
$ printargs $var # Variable is substituted, then its value is parsed into separate words
<one>
<two>
$ printargs "$var" # Double-quotes here allow the variable to be expanded, but prevent further parsing
<one two>
$ printargs '$var' # Single-quotes prevent even variable expansion
<$var>
If you escape the quotes, however, they don't have any of these effects; they're just treated as parts of the argument:
$ printargs \"one\" \'two\' \"three four\"
<"one">
<'two'>
<"three>
<four">
$ printargs \"$var\"
<"one>
<two">
...this is almost never what you want. In particular, with the find
command:
$ searchpath=.
$ filepat='*'
$ greppattern='#ifdef'
$ printargs "$searchpath" -name "$filepat.[ch]" -exec grep --color -aHn "$greppattern" {} \;
<.>
<-name>
<*.[ch]>
<-exec>
<grep>
<--color>
<-aHn>
<#ifdef>
<{}>
<;>
$ printargs "$searchpath" -name \"$filepat.[ch]\" -exec grep --color -aHn \"$greppattern\" {} \;
<.>
<-name>
<"*.[ch]">
<-exec>
<grep>
<--color>
<-aHn>
<"#ifdef">
<{}>
<;>
...in the second one (with escaped quotes) the quotes are passed to find
and it treats them as part of the filename pattern, looking for files with double-quotes in the name. If it manages to find any, the same thing would happen with the grep
command -- it'd be looking for #ifdef's with double-quotes around them.