2015-02-12 10 views
6

Voglio utilizzare una stringa per controllare un ciclo for in bash. Il mio primo codice di test produce ciò che mi aspetterei e ciò che voglio:per il controllo del loop in bash utilizzando una stringa

$ aa='1 2 3 4' 
$ for ii in $aa; do echo $ii; done 
1 
2 
3 
4 

Vorrei invece utilizzare qualcosa come il seguente. Questo non dà l'output che mi piacerebbe (capisco perché fa quello che fa).

$ aa='1..4' 
$ for ii in $aa; do echo $ii; done 
1..4 

Qualche suggerimento su come dovrei modificare il secondo esempio per fornire lo stesso risultato del primo?

Grazie in anticipo per qualsiasi pensiero. Sto imparando lentamente bash, ma ho ancora molto da imparare.

Mike

+3

Perché si desidera utilizzare una stringa per creare una sequenza di numeri? Puoi dare un esempio dove 'for ((i = 1; i <5; i ++)); fare …; fatto' è insufficiente? – kojiro

risposta

1

Bash non farà brace expansion con le variabili, ma è possibile utilizzare eval:

$ aa='1..4' 
$ for ii in $(eval echo {$aa}); do echo $ii; done 
1 
2 
3 
4 

si potrebbe anche dividere aa in un array:

IFS=. arr=($aa) 
for ((ii=arr[0]; ii<arr[2]; ii++)); do echo $ii; done 

noti che IFS può essere solo un singolo carattere, quindi l'intervallo .. inserisce i numeri negli indici 0 e 2.

2

La notazione potrebbe essere scritta come:

for ii in {1..4}; do echo "$ii"; done 

ma il {1..4} deve essere scritto in quel modo, non variabili in gioco, e non come il risultato di una sostituzione di variabile. Questo è brace expansion nel manuale Bash, e capita prima di espansioni a corda, ecc probabilmente sarete meglio fuori usando:

for ii in $(seq 1 4); do echo "$ii"; done 

in cui o il 1 o 4 o entrambi possono essere variabili di shell.

+1

L'uso di 'seq' mi fa dubitare dell'intera cosa _string_, dal momento che un ciclo' for' aritmetico è quasi certamente migliore. – kojiro

+1

Questo è un altro modo per farlo, @kojiro, di sicuro. Potrebbe essere meglio. Tendo ancora ad usare le notazioni di shell che non sono esclusive di Bash, ma la domanda è taggata 'bash' in modo da poterla fornire come risposta alternativa. –

+0

Anche in questo caso, non accetta una stringa come input. – h7r

2

È possibile utilizzare il comando seq (vedere man seq).

$ aa='1 4' 
$ for ii in $(seq $aa); do echo $ii; done 
+0

Questo non accetta una stringa come input come descritto dalla domanda. – h7r

0

Nota ci sono sicuramente modi più eleganti di fare questo, come la risposta di Ben Grimm, e questo non è pura bash, come usa seguenti e awk.

Un modo per ottenere ciò è chiamando il numero seq. Sarebbe banale se conoscessi i numeri nella stringa in anticipo, quindi non ci sarebbe bisogno di fare alcuna conversione, come potresti fare semplicemente seq 1 4 o seq $a $b per quella materia.

Presumo, tuttavia, che l'input sia effettivamente una stringa nel formato che hai citato, ovvero 1..4 o 20..100. A tale scopo è possibile convertire la stringa in 2 numeri e usarli come parametri per seq.

Uno dei molti possibili modi di raggiungere tale obiettivo è:

$ `echo "1..4" | sed -e 's/\.\./ /g' | awk '{print "seq", $1, $2}'` 
1 
2 
3 
4 

noti che questa funziona allo stesso modo per qualsiasi ingresso nel formato indicato. Se lo si desidera, sed può essere modificato da tr con risultati simili.

$ x="10..15" 
$ `echo $x | tr "." " " | awk '{print "seq", $1, $2}'` 
10 
11 
12 
13 
14 
15 
Problemi correlati