arrayslinuxbashshellfind

find: paths must precede expression: `\)'


I'm trying to implement simple wrapper for find to find files, links or both. Here is path of my code:

typeArr=()
if [[ "$type" == "f" || "$type" == "l" ]]; then
    typeArr=("-type" "$type")
elif [[ "$type" == "b" ]]; then
    typeArr=("\(" "-type" "f" "-o" "-type" "l" "\)")
fi
mapfile -t targetFilesArray < <(find "$targetDir" "${typeArr[@]}" -name "${prefix}*" -exec basename {} \;)

Everything is working with f or l, but with b (both) I'm getting this error:

find: paths must precede expression: `\)'

When I paste array content manually - all good:

find "$targetDir" \( -type f -o -type l \) -name "${prefix}*"
/srv/...

echo "${typeArr[@]}"
\( -type f -o -type l \)

find "$targetDir" "${typeArr[@]}" -name "${prefix}*"
find: paths must precede expression: `\)'

Looks like this problem comes from inserting escaped parentheses into find command, but I haven't find a way to fix it (except of not using array and simply insert them into command itself).


Thanks for help, I removed escaping (quotes will work too) and all good:

typeArr=("(" "-type" "f" "-o" "-type" "l" ")")

Solution

  • If you use ( and ) in command line bash will try to create an array,
    So you have to escape it with \ so they are given to find as ( ) and not an array of the args in between.
    But when you put () in a sting (between quotes) bash will not interpret them. so you don't need to escape them.

    If you want to use array you will do without escape because they are in between quotes:

    typeArr=('(' '-type' 'f' '-o' '-type' 'l' ')')
    

    ̶O̶t̶h̶e̶r̶w̶i̶s̶e̶ ̶y̶o̶u̶ ̶c̶a̶n̶ ̶d̶o̶ ̶w̶i̶t̶h̶ ̶s̶i̶m̶p̶l̶e̶ ̶s̶t̶i̶n̶g̶s̶ ̶(̶n̶o̶ ̶a̶r̶r̶a̶y̶,̶ ̶m̶o̶r̶e̶ ̶r̶e̶a̶d̶a̶b̶l̶e̶ ̶i̶ ̶t̶h̶i̶n̶k̶)̶:̶
    More readable but less secure without array :

    typeArr=()
    if [[ "$type" == "f" || "$type" == "l" ]]; then
        typeArg="-type $type"
    elif [[ "$type" == "b" ]]; then
        typeArg='-type f -o -type l'
    else
        echo 'Error: Unknow type'
    fi
    mapfile -t targetFilesArray < <(find "$targetDir" $typeArg -name "${prefix}*"" -exec basename {} \;)
    

    In this case you can see that $typeArg have no quotes because you want to give find multiple args not just one strings