En bash, ¿es posible usar una variable entera en el control de bucle de un bucle for?

65

Tengo el siguiente script bash:

#!/bin/bash

upperlim=10

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

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

El primer forbucle ( sin la variable upperlimen el control del bucle) funciona bien, pero el segundo forbucle ( con la variable upperlimen el control del bucle) no. ¿Hay alguna manera de que pueda modificar el segundo forbucle para que funcione? Gracias por tu tiempo.

Andrés
fuente
44
hm, incluso for i in {0..$((upperlim))}; do echo $i; doneno funciona
Bonsi Scott
y +1 porque encuentro ese comportamiento interesante
Bonsi Scott
posible duplicado entre sitios de: stackoverflow.com/questions/169511/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Un enlace externo que responde a esto: cyberciti.biz/faq/…
kon psych

Respuestas:

62

La razón de esto es el orden en que ocurren las cosas en bash. La expansión de llaves se produce antes de que se expandan las variables. Para lograr su objetivo, debe usar el estilo C para el bucle:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done
jordanm
fuente
1
Y trabaja para zshasí (pero no para csh, tcsh).
Matemáticas el
29

Para completar esto en su estilo usando nada más que elementos integrados, deberá usar eval:

d=12

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

Pero con seq:

lowerlimit=0
upperlimit=12

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

Personalmente, encuentro que el uso de seqes más legible.

Jodie C
fuente
Para "incorporados"? seqes un comando externo y no está disponible en todas partes bash es.
jordanm
99
@jordanm: para usar todos los builtins con bash. Luego dije "pero con seq", reconociendo que no es una función integrada.
Jodie C
El hecho de que la expansión del aparato ortopédico esté incorporado no es el problema aquí. reades un incorporado, por ejemplo, pero no hay razón para evalello.
jordanm
1
Las incorporaciones no son problemáticas en absoluto. Quería proporcionar una solución completa para el autor de la pregunta. Si quieres seguir discutiendo sobre esto, llévalo al chat; los comentarios no son buenos para este tipo de cosas
Jodie C
8

La manera POSIX

Si le importa la portabilidad, use el ejemplo del estándar POSIX :

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

Salida:

2
3
4
5

Cosas que no son POSIX:

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
fuente
1

Su enfoque no funcionará ya que en bash brace-expansion ocurre antes de la expansión de parámetros. Necesita expandir la variable antes.

Puede trabajar con eval :

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

Con el bucle While :

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

También puedes hacerlo con el comando seq :

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

Si desea ejecutar con for i in {0..$upperlim}, necesitará usar kornshell. p.ej:

#!/bin/ksh
upperlim=10

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