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.

Andrew
fonte
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
jordanm
fonte
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.

Jodie C
fonte
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:

Ciro Santilli adicionou uma nova foto
fonte
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
Kheshav Sewnundun
fonte