In bash, è possibile usare una variabile intera nel controllo loop di un ciclo for?


65

Ho il seguente script bash:

#!/bin/bash

upperlim=10

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

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

Il primo forloop ( senza la variabile upperlimnel controllo loop) funziona bene, ma il secondo forloop ( con la variabile upperlimnel controllo loop) no. Esiste un modo per modificare il secondo forloop in modo che funzioni? Grazie per il tuo tempo.


4
hm, anche for i in {0..$((upperlim))}; do echo $i; donenon funziona
Bonsi Scott,

e +1 perché trovo questo comportamento interessante
Bonsi Scott,


Un link esterno che risponde a questa domanda
kon psych

Risposte:


62

La ragione di ciò è l'ordine in cui le cose accadono in bash. L'espansione del controvento si verifica prima dell'espansione delle variabili. Per raggiungere il tuo obiettivo, devi usare lo stile C per il loop:

upperlim=10

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

1
E funziona anche per zsh(ma non per csh, tcsh).
matematica

29

Per completare questo nel tuo stile usando nient'altro che i built-in dovresti usare eval:

d=12

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

Ma con seq:

lowerlimit=0
upperlimit=12

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

Personalmente trovo che l'uso di seqsia più leggibile.


Per "built-in"? seqè un comando esterno e non è disponibile ovunque sia bash.
Giordania,

9
@jordanm: per usare tutti i builtin con bash. Poi ho detto "ma con seq", riconoscendo che non è un built-in.
Jodie C,

Il fatto che l'espansione del controvento sia incorporato non è un problema qui. readè un builtin per esempio, ma non c'è motivo per evalfarlo.
Giordania,

1
I builtin non sono affatto problematici. Volevo fornire una soluzione all-bash per il richiedente. Se vuoi continuare a discutere su questo, portalo in chat; i commenti non vanno bene per questo genere di cose
Jodie C

8

Il modo POSIX

Se ti interessa la portabilità, usa l' esempio dello standard POSIX :

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

Produzione:

2
3
4
5

Cose che non sono POSIX:


1

Il tuo approccio non funzionerà poiché in bash l'espansione del controvento si verifica prima dell'espansione dei parametri. È necessario espandere la variabile prima.

Puoi aggirare con eval :

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

Con ciclo While :

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

Inoltre puoi farlo con il comando seq :

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

Se vuoi correre con for i in {0..$upperlim}te dovrai usare kornshell. per esempio:

#!/bin/ksh
upperlim=10

for i in {0..$upperlim}
do
        echo $i
done
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.