Dazed and confused...need help

I have one script - two versions; these are test scripts to solve my problem/issue.
The difference between the two scripts is that the "for....loop" in script 'loop1' uses a variable ($xlim) to control the loop; whereas in script 'loop2' the loop parameter are fixed integers.

'loop1'
-------------------------------------------------------

#!/bin/bash

zz=3
yy=0
xlim=5

for i in {1..$xlim}; do 
   echo "I = $i"
   ((yy=$zz\*i))
   echo "Welcome $i times  $yy"
done

-------------------------------------------------------------
OUTPUT:

$ loop1
I = {1..5}
./loop1: line 9: ((: {1..5}: syntax error: operand expected (error token is "{1..5}")
Welcome {1..5} times  0

===================================

'loop2'
------------------------------------------------------------

#!/bin/bash

zz=3
yy=0
xlim=5

for i in {1..5}; do 
   echo "I = $i"
   ((yy=$zz\*i))
   echo "Welcome $i times  $yy"
done

---------------------------------------------------------------------

OUTPUT

$ loop2
I = 1
Welcome 1 times  3
I = 2
Welcome 2 times  6
I = 3
Welcome 3 times  9
I = 4
Welcome 4 times  12
I = 5
Welcome 5 times  15

=====================

Of course, my actual script needs a 'parametric loop' like in script 'loop1'.
So why if one of the loop parameters is not a 'static' (constant) value does " I = {1..5} " and not " I = 1 ", i.e why does $i substitute to " {1..5} "?

I have not been able to find any help otherwise and would appreciate any advice!

if we look into man bash and search for Brace Expansion :

       A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or  a
       valid sequence expression.  Any incorrectly formed brace expansion is left unchanged.  A { or , may be quoted with a back
       slash to prevent its being considered part of a brace expression.  To avoid conflicts with parameter expansion, the string
       ${ is not considered eligible for brace expansion.

One possible workaround could be:

#!/usr/bin/bash
#set -x

zz=3
yy=0
xlim=5

for i in $(eval echo {1..${xlim}}) ; do
   echo "I = $i"
   ((yy=zz * i))
   echo "Welcome $i times  $yy"
done

{1..9} just doesn't work that way. You can't stuff numbers into it.

How about a real loop:

for ((i=1; i<=xlim; i++))
do
...
done

or the old fashioned way:

i=1
while [ "$i" -lt "$xlim" ]
do
...
        i=$((i+1))
done
2 Likes

The observed behaviour can be understood by carefully reading the man page, e.g. man bash :

As laid out, brace expansion is the first to take place, and it needs x and y to integers or characters, NOT variable references, which in turn make it fail and leave the construct unchanged (resulting in one single element (literal " {1..$xlim} ") in the for loop and leading to the error message that you see in your post).

Others have shown before that you could use (the highly deprecated because inherently dangerous) eval to get the desired results, or e.g. use the seq command for your for loop:

$ for i in $(seq 1 5); do echo $i; done
1
2
3
4
5
1 Like

Corona668 THX for the advice; sometimes I forget to use "c" type constructs.

You can't do that in bash however if you really need to do something like {1..5} then this is a workaround. Not recommended though...
Longhand using OSX 10.14.1, default bash terminal...

Last login: Tue Jan 15 22:54:14 on ttys000
AMIGA:amiga~> x={1..5}
AMIGA:amiga~> for y in $( eval "echo ${x}" ); do echo "$y"; done
1
2
3
4
5
AMIGA:amiga~> _