Instead of piping the output of find through grep, you might as well use the full capabilities of find. You'll want to build up a an array that contains the options:
-false -o -name '*string1*' ... -o -name '*stringn*'
to pass to find (where string1 ... stringn are the strings passed as arguments):
f() {
local i args=( -false )
for i; do
args+=( -o -name "*$i*" )
done
find "${args[@]}"
}
We're using -false as an initializer, so that building up the array of options is simple; this also has the benefit (or flaw, depending on your point of view) that if no options are given then find exits early without listing all the content of the directory recursively.
With grep you could use regexes to have more powerful matching capabilities; here we're using find's -name option, so we can only use the basic globs: *, ? and [...]. If your find supports the -regex option (GNU find does), and if you really need regexes, then it's trivial to modify the previous function.
Another possibility is to use Bash's extended globs:
f() (
IFS='|' eval 'glob="$*"'
shopt -s globstar extglob nullglob
IFS=
printf '%s\n' **/*@($glob)*
)
A few things to note here:
- The whole function is included in a subshell—it's not a typo. That's to simplify a few things: no need to use local variables, and no need to save the shell options to restore them at the end of the function.
- The first line uses the evil
eval but in a safe way: it's actually an idiomatic way to join the elements of the positional parameters with the first character of IFS (here a pipe character).
- We need to set
IFS to the empty string so as to avoid word splitting in the glob **/*@($glob)*.
- The glob
**/*@($glob)* uses globstar and the extglob @($glob) (with no quotes, it's not a typo). See Pattern Matching in the reference manual.
This function uses Bash's extended globs, that differ from (and aren't as powerful as) regexes (yet this should be enough for most cases).
grep -r