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

60

Eu tenho o seguinte script:

#!/bin/bash

upperlim=10

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

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

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

    
por Andrew 10.11.2012 / 21:24

4 respostas

58

A razão para isso é a ordem na qual as coisas ocorrem no bash. A expansão de contraventamento 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
    
por 10.11.2012 / 21:40
26

Para concluir isso no seu estilo usando nada além de recursos internos, você teria que usar o 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 que o uso de seq é mais legível.

    
por 10.11.2012 / 21:40
6

O caminho POSIX

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

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

Saída:

2
3
4
5

Coisas que não são POSIX:

  • (( )) sem dólar, embora seja uma extensão comum mencionada pelo próprio POSIX .
  • %código%. [[ é o suficiente aqui. Veja também: link
  • [
  • for ((;;))
  • seq , e isso não pode funcionar com variáveis como mencionado pelo manual de Bash .
  • {start..end} : POSIX 7 2. A linguagem de comandos da Shell não contém a palavra let i=i+1 e falha em let 4.3.42
  • o dólar em bash --posix pode ser necessário, mas não tenho certeza. POSIX 7 2.6.4 Expansão aritmética diz:

    If the shell variable x contains a value that forms a valid integer constant, optionally including a leading plus or minus sign, then the arithmetic expansions "$((x))" and "$(($x))" shall return the same value.

    mas lendo literalmente isso não significa que i=$i+1 se expande, pois $((x+1)) não é uma variável.

por 18.11.2015 / 09:48
1

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

Você pode contornar eval :

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

Com o While loop :

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

Você também pode fazer isso com o comando seq :

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

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

#!/bin/ksh
upperlim=10

for i in {0..$upperlim}
do
        echo $i
done
    
por 18.11.2015 / 10:57