LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   BASH:question about for i in {a..b} (https://www.linuxquestions.org/questions/programming-9/bash-question-about-for-i-in-%7Ba-b%7D-4175427081/)

cristalp 09-13-2012 10:52 AM

BASH:question about for i in {a..b}
 
Dear Experts,

With the code
Code:

#!/bin/bash
max=5
for i in {1..$max}
do
  echo "Welcome $i times"
done

I would expect for result like
Code:

Welcome 1 times
Welcome 2 times
Welcome 3 times
Welcome 4 times
Welcome 5 times

However, in fact it printed out me
Code:

Welcome {1..5} times
How could I get correct multiple printout with variable such as $max in for i in {*..*} ?

I would thank for your help.

PTrenholme 09-13-2012 12:26 PM

The problem is that the brace expansion is done before the parameter expansion.
Code:

$ for i in "Welcome "{1..5}" times.";do echo ${i};done
Welcome 1 times.
Welcome 2 times.
Welcome 3 times.
Welcome 4 times.
Welcome 5 times.
$ j=5;for i in "Welcome "{1..$j}" times.";do echo ${i};done
Welcome {1..5} times.

<edit>
As a work-around, this might help:
Code:

#!/bin/bash
max=5
for i in $(echo "for (i=1;i<=${max};++i)i"|bc)
do
  echo "Welcome ${i} times"
done

which produces this:
Code:

$ bash tmp3
Welcome 1 times
Welcome 2 times
Welcome 3 times
Welcome 4 times
Welcome 5 times

</edit>

H_TeXMeX_H 09-13-2012 01:14 PM

Well, I tend to use seq for for loops. In fact I don't use a lot of bash structures, because I have no need of them (and they are confusing and I don't remember them).

Code:

bash-4.1$ j=5;for i in $(seq 1 $j);do echo Welcome $i times.;done
Welcome 1 times.
Welcome 2 times.
Welcome 3 times.
Welcome 4 times.
Welcome 5 times.

Probably someone will post how it should be done with expansion.

divyashree 09-15-2012 01:21 AM

Quote:

Originally Posted by cristalp (Post 4779524)
Dear Experts,

With the code
Code:

#!/bin/bash
max=5
for i in {1..$max}
do
  echo "Welcome $i times"
done

I would expect for result like
Code:

Welcome 1 times
Welcome 2 times
Welcome 3 times
Welcome 4 times
Welcome 5 times

However, in fact it printed out me
Code:

Welcome {1..5} times
How could I get correct multiple printout with variable such as $max in for i in {*..*} ?

I would thank for your help.

Try with this:

Code:

max=5
for ((i=1;i<=max;i++))
do
  echo "Welcome $i times"
done


the_gripmaster 09-16-2012 04:17 AM

I don't think you can do this unless you use the alternative forms posted by the others.

Quoting from http://www.gnu.org/software/bash/man...xpansion.html: "Brace expansion is performed before any other expansions, and any characters special to other expansions are preserved in the result." So $max is evaluated only after the brace expansion is done.

You can see the difference here:

Code:

$ bash -x
...truncated...
$ max=5
+ max=5
$
$ for i in {1..$max}; do echo "Welcome $i times"; done
+ for i in '{1..$max}'
+ echo 'Welcome {1..5} times'
Welcome {1..5} times
$
$ for i in {1..5}; do echo "Welcome $i times"; done
+ for i in '{1..5}'
+ echo 'Welcome 1 times'
Welcome 1 times
+ for i in '{1..5}'
+ echo 'Welcome 2 times'
Welcome 2 times
+ for i in '{1..5}'
+ echo 'Welcome 3 times'
Welcome 3 times
+ for i in '{1..5}'
+ echo 'Welcome 4 times'
Welcome 4 times
+ for i in '{1..5}'
+ echo 'Welcome 5 times'
Welcome 5 times
$

I tried forcing max to be an int using declare -i max but that did not help either.

David the H. 09-16-2012 04:20 AM

This is common Bash Pitfall #33

http://mywiki.wooledge.org/BashPitfa..._.7B1...24n.7D


Quite a few problems like this come down to the shell's parsing order. It really helps to clearly understand what happens before what when a command line is executed.

I've often thought it would be nice though if bash could implement a shell option to enable variable expansion inside brace expansion. It would make some coding situations much easier. But I suppose it would probably be kind of tricky to implement internally, due to the need to account for parameter expansion braces.

And nobody suggest using eval please, ok?


Incidentally, another option for printing simple sequences like this is to use seq's (at least the gnu version's) format option.

Code:

seq -f 'Welcome %g times.' "$n"


All times are GMT -5. The time now is 12:22 PM.