2009-09-18 38 views
133

he conseguido lo siguiente para trabajar:Shell script "para" la sintaxis del bucle

for i in {2..10} 
do 
    echo "output: $i" 
done 

Produce un montón de líneas de output: 2, output: 3, etcétera.

Sin embargo, tratando de ejecutar el siguiente:

max=10 
for i in {2..$max} 
do 
    echo "$i" 
done 

produce lo siguiente:

output: {2..10} 

¿Cómo puedo obtener el compilador para darse cuenta de que debe tratar a $ máx como el otro extremo de la matriz y no parte de una cadena?

+2

qué sistema y la cáscara se utiliza? ¿Qué tipo de sistema tonto tiene sh o bash, pero no tiene seq, un coreutil? – whatsisname

+9

FreeBSD no lo hace. –

+0

'echo" $ i' debe ser 'echo" $ i '' - no solucionará el problema. –

Respuesta

162

Expansión de la abrazadera, {x..y} se realiza antes de otras expansiones, por lo que no puede usar eso para secuencias de longitud variable.

En su lugar, utilice el método seq 2 $max como user mob stated.

Así que, por su ejemplo sería:

max=10 
for i in `seq 2 $max` 
do 
    echo "$i" 
done 
+0

No hay una buena razón para usar un comando externo como 'seq' para contar e incrementar números en el ciclo for, por lo tanto, se recomienda que evite el uso de' seq'. el comando se deja para compatibilidad con viejo bash. Los comandos incorporados son lo suficientemente rápidos. 'para ((EXP1; EXP2; EXP3)) ...' – miller

+6

@ miller la sintaxis 'for ((...))' no es POSIX y eso significa, por ejemplo, que no funcionará de manera automática en cosas como Alpine Linux. 'seq' hace. – Wernight

7

Si el comando seq disponibles en el sistema:

for i in `seq 2 $max` 
do 
    echo "output: $i" 
done 

Si no es así, a continuación, utilizar pobre hombre seq con perl:

seq=`perl -e "\$,=' ';print 2..$max"` 
for i in $seq 
do 
    echo "output: $i" 
done 

Ver las comillas.

+0

Acabo de comprobar eso, no parece que lo sea. – eykanal

0

Bueno, ya que no tengo el comando seq instalado en mi sistema (Mac OS       X v10.6.1 (Snow Leopard  )), que terminé usando un bucle en lugar while:

max=5 
i=1 

while [ $max -gt $i ] 
do 
    (stuff) 
done 

* encoge de hombros * Cualquier cosa que funcione.

+2

seq es relativamente nuevo. Solo me enteré hace unos meses. ¡Pero tú * puedes * usar un ciclo 'para'! La desventaja de un 'while' es que debe recordar incrementar el contador en algún lugar dentro del bucle, o de lo contrario, realizar un bucle hacia abajo. –

22

Paso del bucle de forma manual:

 
i=0 
max=10 
while [ $i -lt $max ] 
do 
    echo "output: $i" 
    true $((i++)) 
done 

Si usted no tiene que ser totalmente POSIX, puede utilizar la aritmética de bucle:

 
max=10 
for ((i=0; i < max; i++)); do echo "output: $i"; done 

O utilice jota (1) en sistemas BSD:

 
for i in $(jot 0 10); do echo "output: $i"; done 
+1

+1 para jot, que debería estar disponible en MacOS: http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/jot.1.html –

+3

'true $ ((i ++)) 'no funciona en todos los casos, por lo que la mayoría de los portátiles serían' true $ ((i = i + 1)) '. – Flow

+0

semi colon no debería entrar en "for ((i = 0; i logan

47

Prueba la versión aritmética-expresión de for:

max=10 
for ((i=2; i <= $max; ++i)) 
do 
    echo "$i" 
done 

Esto está disponible en la mayoría de versiones de golpe, y debe ser compatible shell Bourne (sh) también.

+14

Buena respuesta, pero esto no funciona con '#!/Bin/sh'. – Flow

+1

@Flow: ¡Hm, acabo de probarlo en un par de sistemas (basados ​​en Linux y BSD) con #!/ bin/sh y funcionó bien. Invocado bajo bash y específicamente bajo/bin/sh, todavía funcionó. Tal vez la versión de sh importa? ¿Estás en un viejo Unix? –

+0

AFAIK QNX 6.3.0 – Flow

7

Hay más de una forma de hacerlo.

max=10 
for i in `eval "echo {2..$max}"` 
do 
    echo "$i" 
done 
+5

Un riesgo de seguridad, ya que 'eval' evaluará * cualquier cosa * que configure 'max'. Considere 'max =" 2}; echo ha; # "', luego reemplace 'echo ha' con algo más destructivo. – chepner

+4

(S) estableció un máximo de 10. Sin riesgo. –

0

Uso:

max=10 
for i in `eval echo {2..$max}` 
do 
    echo $i 
done 

Es necesario el 'eval' explícita llamar a reevaluar la sustitución de variables {} después.

1

Aquí funcionó en Mac OS     X.

Incluye el ejemplo de una fecha BSD, la forma de incremento y decremento de la fecha también:

for ((i=28; i>=6 ; i--)); 
do 
    dat=`date -v-${i}d -j "+%Y%m%d"` 
    echo $dat 
done 
2

Esta es una manera:
Bash:

max=10 
for i in $(bash -c "echo {2..${max}}"); do echo $i; done 

La forma Bash anterior funcionará para ksh y zsh también, cuando bash -c se reemplaza por ksh -c o zsh -c respectivamente.

Nota: for i in {2..${max}}; do echo $i; done funciona en zsh y ksh.

1

Todos estos hacen {1..8} y todos deben ser POSIX. Tampoco se romperán si pone un continue condicional en el bucle. La forma canónica:

f= 
while [ $((f+=1)) -le 8 ] 
do 
    echo $f 
done 

Otra forma:

g= 
while 
    g=${g}1 
    [ ${#g} -le 8 ] 
do 
    echo ${#g} 
done 

y otro:

set -- 
while 
    set $* . 
    [ ${#} -le 8 ] 
do 
    echo ${#} 
done