90

I have the following bash script:

#!/bin/bash

upperlim=10

for i in {0..10}
do
echo $i
done

for i in {0..$upperlim}
do
echo $i
done

The first for loop (without the variable upperlim in the loop control) works fine, but the second for loop (with the variable upperlim in the loop control) does not. Is there any way that I can modify the second for loop so that it works? Thanks for your time.

ilkkachu
  • 138,973
Andrew
  • 16,855

5 Answers5

87

The reason for this is the order in which things occur in bash. Brace expansion occurs before variables are expanded. In order to accomplish your goal, you need to use C-style for loop:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done
jordanm
  • 42,678
39

To complete this in your style using nothing but built-ins you'd have to use eval:

d=12

for i in `eval echo {0..$d}`
do
echo $i
done

But with seq:

lowerlimit=0
upperlimit=12

for i in $(seq $lowerlimit $upperlimit)
do
echo $i
done

Personally I find the use of seq to be more readable.

Jodie C
  • 1,879
12

The POSIX way

If you care about portability, use the example from the POSIX standard:

i=2
END=5
while [ "$i" -le "$END" ]; do
    echo "$i"
    i=$(($i+1))
done

Output:

2
3
4
5

Things which are not POSIX:

ilkkachu
  • 138,973
Ciro Santilli OurBigBook.com
  • 18,092
  • 4
  • 117
  • 102
2

Your approach will not work since in bash brace-expansion occurs before parameter expansion. You need to expand the variable before.

You can work around with eval:

upperlim=10
eval '
        for i in {0..'"$upperlim"'}
        do
                echo $i
        done
'

With While loop:

upperlim=10
#with while
start=0
while [[ $start -le $upperlim ]]
do
    echo "$start"
    ((start = start + 1))
done

Also you can do it with seq command:

upperlim=10
#seq
for i in $(seq "$upperlim"); do
  echo "$i"
done

If you want to run with for i in {0..$upperlim} you will need to use kornshell. eg:

#!/bin/ksh
upperlim=10

for i in {0..$upperlim}
do
        echo $i
done
0
for i in $(seq ${1:-1} ${2:-10}); do                                            
        echo $i                                                                 
done 



i=${1:-1}                                                                       
while (( $i <= ${2:-10} )); do                                                  
        echo $i                                                                 
        i=$(($i + 1))                                                           
done
  • Welcome to the site, and thank you for your contribution. Please note however that your answer would benefit from some more explanation on what it is you are doing and how and why this contributes to answering the original question. – AdminBee Jan 03 '23 at 14:15