Bash globbing of multi-part argument

bashwildcards

Below are some examples of a find command I'm trying to run. I'm looking for different ways that I might be able to use globbing to generate (as an example) a find command with predicates joined together.

Doesn't work because find needs a -name before each one and a -o between each.

find . -name \*.{sh,pl,sql}
#find . -name *.sh *.pl *.sql

Doesn't work because of trailing -o. Could pull a guaranteed to fail argument there, but not ideal. Also, my shortcut is now longer than my output.

find . `for X in {sh,pl,sql}; do echo -name \\\*.$X -o ;done`
#find . -name \*.sh -o -name \*.pl -o -name \*.sql -o

Fails because they're grouped as one argument (find: unknown predicate '-name *.sh'). Also, still exhibiting a lack of joining with -o.

find . -name\ \*.{sh,pl,sql}

Works, but doesn't involve globbing (re: non-answer):

find .  -regex '.*\(sh\|pl\|sql\)'    

Best Answer

The -false idea is the key, IMHO. I'm just adding to it:

find . -false $(echo "-o -name *."{sh,pl,sql})

You just quote everything to make bash repeat the whole pattern, including -o -name, and then "break" the grouping made by the quoting by returning it from a subshell. The problem with this approach is that quotes in the pattern won't work.


EDIT: See Michał Šrajer's comment for another pitfall of this solution. Note that you can't just put a backslash before the star: the command substitution returns either a *, which will get expanded, or a \*, which will get passed as-is to find (!). At least, that's how my local bash works.

This is the best I can do:

 (GLOBIGNORE='*:.*'; find . \( -false $(echo "-o -name *."{sh,pl,sql,xml}) \) -print)

Good luck :)

Btw, if you are not going to add more parameters to find, of course just use xargs; in that case it works perfectly, with quotes and everything:

echo "-o -name *."{sh,pl,sql} | xargs find . -false
Related Question