5

I am trying to write a bash script. I am not sure why in my script:

ls {*.xml,*.txt} 

works okay, but

name="{*.xml,*.txt}"
ls $name

doesn't work. I get

ls: cannot access {*.xml,*.txt}: No such file or directory
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
twq
  • 53
  • 4
  • 1
    [What are you trying to accomplish?](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – Ignacio Vazquez-Abrams May 03 '17 at 05:15
  • `{*.xml,*.txt}` just expands to `*.xml *.txt`, which expands to the file names matching those patterns, so the first command is just the same as `ls *.xml *.txt`, which really begs the question of what you actually wish to do? – ilkkachu May 03 '17 at 11:11

2 Answers2

4

The expression

ls {*.xml,*.txt}

results in Brace expansion and shell passes the expansion (if any) to ls as arguments. Setting shopt -s nullglob makes this expression evaluate to nothing when there are no matching files.

Double quoting the string suppresses the expansion and shell stores the literal contents in your variable name (not sure if that is what you wanted). When you invoke ls with $name as the argument, shell does the variable expansion but no brace expansion is done.

As @Cyrus has mentioned, eval ls $name will force brace expansion and you get the same result as that of ls {\*.xml,\*.txt}.

codeforester
  • 39,467
  • 16
  • 112
  • 140
  • 1
    in addition: Not only the double quoting but also the variable assignment doesn't support brace expansion. There is no difference between `name="{\*.xml,*.txt}"` and `name={\*.xml,*.txt}` in this case. Expansions (if supported and enabled) are done when reading the command line. – Pinke Helga May 03 '17 at 06:01
  • Thanks. I wanted to add that point but didn't see it being mentioned in the Bash manual. – codeforester May 03 '17 at 06:03
  • [Why should eval be avoided in Bash, and what should I use instead?](http://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead) – ceving May 03 '17 at 07:40
  • Brace expansion results in multiple words, so it cannot sensibly work in an assignment. The expansions done on assignments [are listed in the manual](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameters.html#index-shell-variable). – ilkkachu May 03 '17 at 11:01
1

The reason your expansion doesn't work is that brace expansion is performed before variable expansion, see Shell expansions in the manual.

I'm not sure what it is you're trying to do, but if you want to store a list of file names, use an array:

files=( {*.txt,*.xml} )           # these two are the same
files=(*.txt *.xml)
ls -l "${files[@]}"               # give them to a command
for file in "${files[@]}" ; do    # or loop over them
    dosomething "$file"
done

"${array[@]}" expands to all elements of the array, as separate words. (remember the quotes!)

ilkkachu
  • 6,221
  • 16
  • 30