No bash, é possível usar uma variável inteira no controle de loop de um loop for?


65

Eu tenho o seguinte script bash:

#!/bin/bash

upperlim=10

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

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

O primeiro forloop ( sem a variável upperlimno controle do loop) funciona bem, mas o segundo forloop ( com a variável upperlimno controle do loop) não. Existe alguma maneira de modificar o segundo forloop para que ele funcione? Obrigado pelo seu tempo.


4
hm, mesmo for i in {0..$((upperlim))}; do echo $i; donenão funciona
Bonsi Scott

e +1 porque acho que o comportamento interessante
Bonsi Scott

possível duplicado entre sites: stackoverflow.com/questions/169511/…
Ciro Santilli (

Um link externo que responde a isso: cyberciti.biz/faq/…
kon psych

Respostas:


62

A razão para isso é a ordem na qual as coisas ocorrem no bash. A expansão de chaves ocorre antes que as variáveis ​​sejam expandidas. Para atingir seu objetivo, você precisa usar o estilo C para loop:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done

11
E trabalha para zshbem (mas não para csh, tcsh).
math

29

Para concluir isso no seu estilo usando nada além de embutidos, você teria que usar eval:

d=12

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

Mas com seq:

lowerlimit=0
upperlimit=12

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

Pessoalmente, acho o uso de seqmais legível.


Para "embutidos"? seqé um comando externo e não está disponível em qualquer lugar do bash.
Jordanm

9
@ Jordanm: Para usar todos os builtins com bash. Então eu disse "mas com seq", reconhecendo que não é um built-in.
precisa

O fato de que a expansão da cinta está embutida não é o problema aqui. readé um builtin por exemplo, mas não há razão para evalisso.
jordanm

11
Builtins não são problemáticos. Eu queria fornecer uma solução completa para o solicitante. Se você quiser continuar discutindo sobre isso, leve-o para conversar; comentários não são bons para esse tipo de coisa
Jodie C

8

A maneira POSIX

Se você se preocupa com portabilidade, use o exemplo do padrão POSIX :

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

Resultado:

2
3
4
5

Coisas que não são POSIX:


1

Sua abordagem não funcionará, pois na expansão do suporte do bash ocorre antes da expansão do parâmetro. Você precisa expandir a variável antes.

Você pode contornar o eval :

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

Com o loop While :

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

Além disso, você pode fazê-lo com o comando seq :

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

Se você quiser correr com for i in {0..$upperlim}você, precisará usar o kornshell. por exemplo:

#!/bin/ksh
upperlim=10

for i in {0..$upperlim}
do
        echo $i
done
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.