0

Ubuntu 14.04.5 LTS GNU bash, Version 4.3.11(1)-release (x86_64-pc-linux-gnu)

mkdir -vp test{1..3}/{a,b,c}

works fine

mkdir: created directory 'test1'
mkdir: created directory 'test1/a'
mkdir: created directory 'test1/b'
mkdir: created directory 'test1/c'
mkdir: created directory 'test2'
mkdir: created directory 'test2/a'
mkdir: created directory 'test2/b'
mkdir: created directory 'test2/c'
mkdir: created directory 'test3'
mkdir: created directory 'test3/a'
mkdir: created directory 'test3/b'
mkdir: created directory 'test3/c'


S=1;E=3; LANG=EN mkdir -pv test{$S..$E}/{a,b,c}

mkdir: created directory 'test{1..3}'
mkdir: created directory 'test{1..3}/a'
mkdir: created directory 'test{1..3}/b'
mkdir: created directory 'test{1..3}/c'

seems not to work.

unsucessfull was single and double qouting as well.

S=1;E=3; LANG=EN mkdir -pv 'test{$S..$E}/{a,b,c}'
mkdir: created directory 'test{$S..$E}'
mkdir: created directory 'test{$S..$E}/{a,b,c}'


 S=1;E=3; LANG=EN mkdir -pv 'test{'$S'..'$E'}/{a,b,c}'
 mkdir: created directory 'test{1..3}'
 mkdir: created directory 'test{1..3}/{a,b,c}'

 S=1;E=3; LANG=EN mkdir -pv "test{S1..S3}/{a,b,c}"
 mkdir: created directory 'test{S1..S3}'
 mkdir: created directory 'test{S1..S3}/{a,b,c}'

i know i can use for loops, have limits with the amount of arguments, possible issues with folders, or use printf or similiar setups as shown in the "Similar Questions" parts.

However i rather want to know why this specific case of globbing fails for me.

i found a possible solution in a comment on this question

Bash script single-quotes parameter with globbing value

qouting the user galaxy You can use eval to expand the whole line before executing it, e.g. $out=(eval "grep ..."), however, this works only if your input is trusted. – which makes this

S=1;E=3; LANG=EN eval mkdir -pv "test{$S..$E}/{a,b,c}"

mkdir: created directory 'test1'
mkdir: created directory 'test1/a'
mkdir: created directory 'test1/b'
mkdir: created directory 'test1/c'
mkdir: created directory 'test2'
mkdir: created directory 'test2/a'
mkdir: created directory 'test2/b'
mkdir: created directory 'test2/c'
mkdir: created directory 'test3'
mkdir: created directory 'test3/a'
mkdir: created directory 'test3/b'
mkdir: created directory 'test3/c'

work.

  • 1
    It fails for precisely the reason stated in the first comment in the Q you linked: "Brace expansion happens before variable expansion". If A happens before B then A does not happen after B. (And it is NOT globbing; both globbing, formally Filename Expansion, and Brace Expansion are different and separate Shell Expansions.) – dave_thompson_085 Oct 06 '16 at 13:53

1 Answers1

1

Yep, in Bash, brace expansion is done as about the very first thing, before expanding variables. Which means that this doesn't work as you want:

$ a=1; b=5; echo {$a..$b}
{1..5}

(The braces are expanded first, giving {$a..$b}, then the variables, giving {1..5}.)

But you can do this (if you ever come up with a use for it):

$ aa=123;ab=456; echo $a{a,b}
123 456

Using eval works, since it forces an additional evaluation pass, but it isn't usually a good idea, since it will evaluate e.g. command expansions and others from filenames containing $ signs, which is usually not what you want.

If you have a numeric range, as here, you can use a loop:

S=1;E=3;
for (( i=$S; i <= $E; i++ )) ; do 
     echo $i
done

or:

while [ $S -le $E ] ; do 
    echo $S 
    S=$[ $S + 1] 
done 

Also, zsh does brace expansion as you wanted:

$ zsh -c 'a=1; b=5; echo {$a..$b}'
1 2 3 4 5
ilkkachu
  • 138,973