Jak napisać pętlę for w bash

Odpowiedzi:

106

Z tej strony :

for i in $(seq 1 10);
do
    echo $i
done
Rob Rolnick
źródło
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
63
for ((i = 0 ; i < max ; i++ )); do echo "$i"; done
Nick Stinemate
źródło
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

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

Fernando Barrocal
źródło
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).

David Gardner
źródło
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.


Pat Notz
źródło
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?

Brent Bradburn
źródło
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ą.

terson
źródło
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


źródło
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 .


źródło
Myślę, że masz na myśli opcję -execdir do znalezienia
Wstrzymano do odwołania.