Mike M
Mike M

Reputation: 133

Bash: passing file pattern as an argument to a command through a variable

My apologies if this is already answered, but if it is I can't find the proper search terms.

I'm trying to dynamically define search terms (based on user defined settings) for the find command:

# reading user settings results in array of filename patterns to delete:
patterns=("*.url" "*.html")
for i in ${patterns[@]}; do 
  find . -iname $i -delete
done

If I echo the command, the resulting string looks correct, e.g.

find . -iname "*.url" -delete
find . -iname "*.html" -delete

I know I'm missing something obvious but nothing I've tried works.

I'm using Bash 4.4.5 if that helps.

----------------EDIT-----------------

My thanks to Charles Duffy and l'L'l for the correct solution(s). I had a hard time wrapping my head around the quotes in the array strings vs the quoted variables and failed to quote both variables at the same time.

Lesson learned: always quote shell variables.

Upvotes: 1

Views: 2684

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295687

The answer by l'L'l is a good one, but let's make it a little more efficient, by invoking find only once with all your patterns passed in a single command line:

patterns=("*.url" "*.html")
find_pat=( )

for i in "${patterns[@]}"; do
  find_pat+=( -o -name "$i" )
done

find . -iname '(' "${find_pat[@]:1}" ')' -delete

When run, this will invoke:

find . -iname '(' -name '*.url' -o -name '*.html' ')' -delete

...thus deleting all files which match either *.url or *.html in a single pass.


Note:

  • We're quoting our globs at all times: They're quoted on assignment (so we assign the globs themselves to the patterns array), on array expansion (so we iterate over the globs themselves and not their results), and on expansion into the find command (so we pass find the literal pattern syntax, not the result of expanding that syntax).
  • We're prepending -o to the find_pat array, but then expanding from the second element (arrays being 0-indexed), thus skipping that initial -o. The syntax used here is parameter expansion.

Upvotes: 5

l'L'l
l'L'l

Reputation: 47274

You need to double-quote your variables:

for i in "${patterns[@]}"; do 
    find . -iname "$i" -delete
...

This will prevent globbing and word splitting.

You can always check your script at https://www.shellcheck.net/ for errors as well...

Upvotes: 3

Related Questions