jeśli mamy zmienną, na przykład ArrayLength=${#array[@]}jak jej tutaj używamy zamiast max?
Kasun Siyambalapitiya
34
Bash forskłada się ze zmiennej (iteratora) i listy słów, w których iterator będzie iterował.
Jeśli więc masz ograniczoną listę słów, po prostu umieść je w następującej składni:
for w in word1 word2 word3
do
doSomething($w)
done
Prawdopodobnie chcesz iterować po niektórych liczbach, więc możesz użyć seqpolecenia, aby wygenerować dla siebie listę liczb: (na przykład od 1 do 100)
seq 1 100
i użyj go w pętli FOR:
for n in $(seq 1 100)
do
doSomething($n)
done
Zwróć uwagę na $(...)składnię. Jest to zachowanie basha, pozwala na przekazanie danych wyjściowych z jednego polecenia (w naszym przypadku od seq) do innego ( for)
Jest to naprawdę przydatne, gdy musisz iterować po wszystkich katalogach w jakiejś ścieżce, na przykład:
for d in $(find $somepath -type d)
do
doSomething($d)
done
Dobra odpowiedź, ale możesz chcieć dołączyć for ((i = 0; i <MAX; i ++)); zrobić doSomething ($ i); również wykonany wariant. Myślę, że jest to ogólnie preferowane od for i w wariancie $ (seq 0 MAX), ponieważ ten ostatni najpierw wygeneruje wszystkie liczby od 0 do MAX przed faktycznym wykonaniem pętli.
mweerden
30
Bash 3.0+ może używać tej składni:
for i in {1..10} ; do ... ; done
.. który pozwala uniknąć tworzenia zewnętrznego programu w celu rozszerzenia sekwencji (na przykład seq 1 10).
Oczywiście ma to ten sam problem, co for(())rozwiązanie, przywiązanie do basha, a nawet do konkretnej wersji (jeśli to dla ciebie ważne).
$ helpforfor: for NAME [in WORDS ... ;] do COMMANDS; done
The `for' loop executes a sequence of commands for each member in a
list of items. If `in WORDS ...;' is not present, then `in"$@"' is
assumed. For each element in WORDS, NAME is set to that element, and
the COMMANDS are executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
Equivalent to
(( EXP1 ))
while (( EXP2 )); do
COMMANDS
(( EXP3 ))
done
EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is
omitted, it behaves as if it evaluates to 1.
Nie zauważyłem tego wcześniej, ale podobna składnia jest pokazana w jednej z wcześniejszych odpowiedzi. Unikalną rzeczą jest tutaj użycie nawiasów klamrowych zamiast typowej pary do/ done.
Brent Bradburn
4
Zwykle lubię używać niewielkiego wariantu standardu pętli for. Często używam tego do uruchamiania poleceń na szeregu zdalnych hostów. Korzystam z rozwijania nawiasów klamrowych basha do tworzenia pętli for, które pozwalają mi tworzyć nienumeryczne pętle for.
Przykład:
Chcę uruchomić polecenie uptime na hostach frontendu 1-5 i hostach backendu 1-3:
% for host in {frontend{1..5},backend{1..3}}.mycompany.com
do ssh $host"echo -n $host; uptime"done
Zwykle uruchamiam to jako jednowierszowe polecenie ze średnikami na końcach wierszy zamiast bardziej czytelnej wersji powyżej. Kluczową kwestią dotyczącą użycia jest to, że nawiasy klamrowe pozwalają na określenie wielu wartości, które mają być wstawione do ciągu (np. Pre {foo, bar} wyniki w prefoopost, prebarpost) i pozwalają zliczać / sekwencje przy użyciu podwójnych kropek (możesz użyć. .z itp.). Jednak składnia z dwoma kropkami jest nową funkcją bash 3.0; wcześniejsze wersje tego nie obsługują.
W związku z tym, co się stanie, jeśli $ host var jest przez przypadek pustą linią? Nadal będzie strzelał ssh. Jak więc tego uniknąć? W moim przypadku robię coś innego, więc Twoja odpowiedź mi pomoże. Próbuję sprawdzić, czy w Gmailu nie ma nowych wiadomości, a jeśli zostaną znalezione, wyślij SMS-a na adres od i temat. Moje pytanie jest oznaczone jako „Łączenie dwóch poleceń basowych”, jeśli chcesz je przeczytać.
Volomike
Nie wierzę, że otrzymałeś pustą zmienną $ host. Dzieje się tak, ponieważ powyższy przykład wykorzystuje rozwinięcie nawiasów. Pętla for jawnie ustawia zmienną $ host na wartości: frontend1.mycompany.com frontend2.mycompany.com. . backend1.mycompany.com Ale jeśli zobaczysz sposób, aby miał wartość null; Chciałbym wiedzieć. Możesz wykonać ssh w ramach testu warunkowego, jeśli byłby to problem.
terson
1
jeśli interesuje Cię tylko bash, to rozwiązanie "for ((...))" przedstawione powyżej jest najlepsze, ale jeśli chcesz czegoś zgodnego z POSIX SH, co będzie działać na wszystkich unikach, będziesz musiał użyć "expr" i „while”, a to dlatego, że „(())”, „seq” lub „i = i + 1” nie są tak przenośne między różnymi powłokami
Odpowiedzi:
Z tej strony :
for i in $(seq 1 10); do echo $i done
źródło
for ((i = 0 ; i < max ; i++ )); do echo "$i"; done
źródło
ArrayLength=${#array[@]}
jak jej tutaj używamy zamiastmax
?Bash
for
składa się ze zmiennej (iteratora) i listy słów, w których iterator będzie iterował.Jeśli więc masz ograniczoną listę słów, po prostu umieść je w następującej składni:
for w in word1 word2 word3 do doSomething($w) done
Prawdopodobnie chcesz iterować po niektórych liczbach, więc możesz użyć
seq
polecenia, aby wygenerować dla siebie listę liczb: (na przykład od 1 do 100)i użyj go w pętli FOR:
for n in $(seq 1 100) do doSomething($n) done
Zwróć uwagę na
$(...)
składnię. Jest to zachowanie basha, pozwala na przekazanie danych wyjściowych z jednego polecenia (w naszym przypadku odseq
) do innego (for
)Jest to naprawdę przydatne, gdy musisz iterować po wszystkich katalogach w jakiejś ścieżce, na przykład:
for d in $(find $somepath -type d) do doSomething($d) done
Możliwości generowania list są nieskończone.
źródło
Bash 3.0+ może używać tej składni:
for i in {1..10} ; do ... ; done
.. który pozwala uniknąć tworzenia zewnętrznego programu w celu rozszerzenia sekwencji (na przykład
seq 1 10
).Oczywiście ma to ten sam problem, co
for(())
rozwiązanie, przywiązanie do basha, a nawet do konkretnej wersji (jeśli to dla ciebie ważne).źródło
Wypróbuj
bash
wbudowaną pomoc:$ help for for: for NAME [in WORDS ... ;] do COMMANDS; done The `for' loop executes a sequence of commands for each member in a list of items. If `in WORDS ...;' is not present, then `in "$@"' is assumed. For each element in WORDS, NAME is set to that element, and the COMMANDS are executed. for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done Equivalent to (( EXP1 )) while (( EXP2 )); do COMMANDS (( EXP3 )) done EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is omitted, it behaves as if it evaluates to 1.
źródło
#! /bin/bash function do_something { echo value=${1} } MAX=4 for (( i=0; i<MAX; i++ )) ; { do_something ${i} }
Oto przykład, który może działać również w starszych powłokach, ale nadal jest wydajny w przypadku dużych zliczeń:
Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'
Ale powodzenia w robieniu przydatnych rzeczy wewnątrz
awk
: Jak używać zmiennych powłoki w skrypcie awk?źródło
do
/done
.Zwykle lubię używać niewielkiego wariantu standardu pętli for. Często używam tego do uruchamiania poleceń na szeregu zdalnych hostów. Korzystam z rozwijania nawiasów klamrowych basha do tworzenia pętli for, które pozwalają mi tworzyć nienumeryczne pętle for.
Przykład:
Chcę uruchomić polecenie uptime na hostach frontendu 1-5 i hostach backendu 1-3:
% for host in {frontend{1..5},backend{1..3}}.mycompany.com do ssh $host "echo -n $host; uptime" done
Zwykle uruchamiam to jako jednowierszowe polecenie ze średnikami na końcach wierszy zamiast bardziej czytelnej wersji powyżej. Kluczową kwestią dotyczącą użycia jest to, że nawiasy klamrowe pozwalają na określenie wielu wartości, które mają być wstawione do ciągu (np. Pre {foo, bar} wyniki w prefoopost, prebarpost) i pozwalają zliczać / sekwencje przy użyciu podwójnych kropek (możesz użyć. .z itp.). Jednak składnia z dwoma kropkami jest nową funkcją bash 3.0; wcześniejsze wersje tego nie obsługują.
źródło
jeśli interesuje Cię tylko bash, to rozwiązanie "for ((...))" przedstawione powyżej jest najlepsze, ale jeśli chcesz czegoś zgodnego z POSIX SH, co będzie działać na wszystkich unikach, będziesz musiał użyć "expr" i „while”, a to dlatego, że „(())”, „seq” lub „i = i + 1” nie są tak przenośne między różnymi powłokami
źródło
Cały czas używam odmian tego do przetwarzania plików ...
Jeśli interesuje Cię przetwarzanie list plików, spójrz na opcję -execdir dotyczącą plików .
źródło