2015-02-12 11 views
6

Chcę użyć łańcucha do sterowania pętlą for w bash. Mój pierwszy kod testowy daje to, czego oczekuję i czego chcę:do sterowania pętlą w bashu za pomocą ciągu znaków

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

Zamiast tego chciałbym użyć czegoś takiego. To nie daje wyników, które chciałbym (widzę, dlaczego robi to, co robi).

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

Jakieś sugestie, w jaki sposób powinienem zmodyfikować drugi przykład, aby uzyskać ten sam wynik co pierwszy?

Z góry dziękuję za wszelkie uwagi. Powoli uczę się gry, ale wciąż muszę się wiele nauczyć.

Mike

+3

Dlaczego chcesz użyć ciągu znaków, aby utworzyć ciąg cyfr? Czy możesz podać przykład gdzie 'for ((i = 1; i <5; i ++)); robić …; done' jest niewystarczające? – kojiro

Odpowiedz

1

atakujących nie zrobi brace expansion ze zmiennych, ale można użyć eval:

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

Można również podzielić aa do tablicy:

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

pamiętać, że IFS może być tylko pojedynczym znakiem, więc zakres .. umieszcza liczby w indeksach 0 i 2.

2

Zapis można zapisać jako:

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

ale {1..4} musi być rozpisane tak, żadne zmienne zaangażowany, a nie w wyniku podstawienia zmiennej. To jest brace expansion w instrukcji Bash, a zdarza się przed ekspansji łańcuchowych itp Będziesz prawdopodobnie najlepiej wyłączyć za pomocą:

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

gdzie albo 1 lub 4 lub oba mogą być zmienne powłoki.

+1

Używanie 'seq' sprawia, że ​​kwestionuję całą rzecz _string_, ponieważ arytmetyczna pętla' for' jest prawie na pewno lepsza. – kojiro

+1

To na pewno inny sposób, @kojiro. Może być lepiej. Nadal używam zapisów w powłoce, które nie są wyłączne dla Bash, ale pytanie jest oznaczone jako 'bash', więc możesz podać to jako alternatywną odpowiedź. –

+0

Ponownie, to nie przyjmuje łańcucha jako danych wejściowych. – h7r

2

Można użyć polecenia seq (patrz man seq).

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

To nie przyjmuje łańcucha jako danych wejściowych opisanych w pytaniu. – h7r

0

Uwaga Istnieje z pewnością bardziej eleganckie sposoby robienia tego, jak odpowiedź Ben Grimm, a to nie jest czysta bash, jak wykorzystuje nast i awk.

Jednym ze sposobów osiągnięcia tego jest wywołanie seq. Byłoby banalnie, gdybyś znał numery w łańcuchu z wyprzedzeniem, więc nie byłoby potrzeby dokonywania jakiejkolwiek konwersji, jak można by łatwo zrobić, aby to zrobić.

Zakładam jednak, że twoje dane wejściowe są rzeczywiście ciągiem w wymienionym formacie, to jest 1..4 lub 20..100. W tym celu można przekształcić ciąg na 2 liczby i używać ich jako parametrów dla seq.

Jeden z możliwie wielu sposobów osiągnięcia tego celu jest:

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

Zauważ, że to będzie działać w ten sam sposób dla każdego wejścia w danym formacie. W razie potrzeby można zmienić sed przez tr z podobnymi wynikami.

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