Ubuntu – bash script: {dir1,dir2,dir3} expansion not working as expected from variable, for picking a random file

bashcommand linescripts

I have a problem, with this simple script (pick a random file):

#!/usr/bin/env bash
set -x
srcDir="/home/user/Desktop/wallPapers/{dir1,dir2,dir3}"
randomFile=$(find "$srcDir" -type f -iname "*.jpg" | shuf -n 1)
printf '[%s]\n' $randomFile
set +x

The problem is that while I can type this at the command line (and works perfectly fine):

find /home/user/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg"

Then the bash debugging set-commands (set -x and +x) tells me, that for some reason bash both encloses the directory string with single quotation marks and it also replaces the double quotation marks with single quotation marks?

./script.sh
+ srcDir='/home/user/Desktop/wallPapers/{dir1,dir2,dir3}'
++ find '/home/user/Desktop/wallPapers/{dir1,dir2,dir3}' -type f -iname '"*.jpg"'
find: ‘/home/user/Desktop/wallPapers/{dir1,dir2,dir3}’: No such file or directory
+ randomFile=
+ printf '[%s]\n'
[]
+ set +x

I understand, this is what bash sees, when the script runs:

find '/home/user/Desktop/wallPapers/{dir1,dir2,dir3}' -type -iname '*.jpg'

And this causes the "No such file or directory"-message, very very annoying… I do not understand, why it inserts these single quotation marks, I want double quotation marks used instead, just like on the command line… Could anyone please explain, I would be happy for that, thanks!

Best Answer

Brace expansion doesn't occur within a variable assignment, as explained here:

Why do tilde prefixes expand prior to assignment, but braces don't

In other contexts, the quotes would have prevented brace expansion as well.

Even if you do manage to get srcDir to expand to a list of directories, quoting it again in the find command will cause it to be treated as a single argument instead of 3 separate paths.

Probably the right way to do this in bash is to use an array:

#!/usr/bin/env bash
set -x
srcDir=("/home/user/Desktop/wallPapers/"{dir1,dir2,dir3})
randomFile=$(find "${srcDir[@]}" -type f -iname "*.jpg" | shuf -n 1)
printf '[%s]\n' "$randomFile"
set +x
Related Question