Jak napisać pętlę for w bash


Odpowiedzi:


106

Z tej strony :

for i in $(seq 1 10);
do
    echo $i
done

10
Warto wspomnieć, że podany tutaj zakres jest włącznie . Mam na myśli to, że zobaczysz cały zakres (od 1 do 10) wydrukowany na konsoli.
Jamie


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

Możliwości generowania list są nieskończone.


2
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).


14

Wypróbuj bashwbudowaną 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.



5
#! /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?


2
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


0

Cały czas używam odmian tego do przetwarzania plików ...

dla plików w * .log; do echo "Rób rzeczy z: $ plikami"; echo "Rób więcej z: $ files"; Gotowe;

Jeśli interesuje Cię przetwarzanie list plików, spójrz na opcję -execdir dotyczącą plików .


Myślę, że masz na myśli opcję -execdir do znalezienia
Wstrzymano do odwołania.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.