1

I need to build up an argument list for find using values only known at run time. I'm trying to use an array to do so.

Below is a simplified version which uses hard coded values. When I echo out the command it appears to be correct (and when I run it manually it does what I'd expect). When it enters the for-loop it appears to be running find (because I can see the same errors about Permission denied for directories owned by other users as when I run manually). But inside the for-loop, it doesn't echo out any of the .txt files that a manual run finds.

What did I do wrong?

#!/bin/bash

args=(/tmp -iname \"*.txt\")

#args+=(-o -iname \"*.jpg\")

echo command will be: find ${args[@]}
for f in $( find ${args[@]} ); do
    echo found $f
done

The accepted answer below correctly identified the issue. But if I add an additional -iname clause, my script "ignores" all but the last as detailed here:

#!/bin/bash

args=($1)
args+=(-maxdepth $2)
args+=(-iname "*$3")
args+=(-o -iname "*$4")
echo command will be: find "${args[@]}"

find "${args[@]}" -print 2>/dev/null | while read -r f; do
    echo found "$f"
done

For example, when called with /home/me 2 .jpg .png this correctly echoes that the command will be find /home/me -maxdepth 2 -iname *.jpg -o -iname *.png but then my script only echoes the .png files that it finds.

2

2 Answers 2

3

You shouldn't escape the quotes. That will make them literal, so it will try to find files whose names actually begin and end with doublequotes.

args=(/tmp -iname "*.txt")

Then you need to put quotes around ${args[@]} to tell the shell that it should requote them when expanding the array:

find "(" "${args[@]}" ")" -print | while read -r f
do
    echo found "$f"
done
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. I ran into another issue and added it to the question instead of sticking it in this comment since it allows for better formatting.
When you use -o, you need an action in each branch. I've fixed the answer to put parenthese around everything to group them.
Hm. Actually parens around all the args didn't work for me but parens around just the -iname clauses did. But the other answer that mentioned such parens disappeared...
If you have things in $args that need to be distributed among both branches of the -o, then you need additional levels of parentheses. E.g. if you want -maxdepth to apply to both -iname clauses, you need to put them in parentheses.
1

Bash4 can expand globs recursively with shopt -s globstar.
Just use array=(/tmp/**/*.txt) to get all the elements.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.