Wie schreibe ich eine for-Schleife in bash?

Antworten:

103

Von dieser Seite :

for i in $(seq 1 10);
do
    echo $i
done
Rob Rolnick
quelle
10
Erwähnenswert ist, dass der hier angegebene Bereich inklusive ist . Damit meine ich, dass Sie den gesamten Bereich (1 bis 10) auf der Konsole drucken sehen.
Jamie
62
for ((i = 0 ; i < max ; i++ )); do echo "$i"; done
Nick Stinemates
quelle
Wenn wir eine Variable haben, ArrayLength=${#array[@]}wie verwenden wir sie hier anstelle von max?
Kasun Siyambalapitiya
34

Die Bash forbesteht aus einer Variablen (dem Iterator) und einer Liste von Wörtern, in denen der Iterator iteriert.

Wenn Sie also eine begrenzte Liste von Wörtern haben, geben Sie diese einfach in die folgende Syntax ein:

for w in word1 word2 word3
do
  doSomething($w)
done

Wahrscheinlich möchten Sie einige Zahlen durchlaufen, damit Sie mit dem seqBefehl eine Liste mit Zahlen für Sie erstellen können : (zum Beispiel von 1 bis 100)

seq 1 100

und benutze es in der FOR-Schleife:

for n in $(seq 1 100)
do
  doSomething($n)
done

Beachten Sie die $(...)Syntax. Es ist ein Bash-Verhalten, mit dem Sie die Ausgabe von einem Befehl (in unserem Fall von seq) an einen anderen (den for) übergeben können.

Dies ist sehr nützlich, wenn Sie alle Verzeichnisse in einem bestimmten Pfad durchlaufen müssen, zum Beispiel:

for d in $(find $somepath -type d)
do
  doSomething($d)
done

Die Möglichkeiten, die Listen zu generieren, sind unendlich.

Fernando Barrocal
quelle
2
Gute Antwort, aber vielleicht möchten Sie das for ((i = 0; i <MAX; i ++)) einschließen. do doSomething ($ i); Variante auch gemacht. Ich denke, dies ist im Allgemeinen der Variante für i in $ (seq 0 MAX) vorzuziehen, da letztere zuerst alle Zahlen von 0 bis MAX generiert, bevor die Schleife tatsächlich ausgeführt wird.
Mweerden
30

Bash 3.0+ kann diese Syntax verwenden:

for i in {1..10} ; do ... ; done

..die verhindert, dass ein externes Programm erzeugt wird, um die Sequenz zu erweitern (z. B. seq 1 10).

Dies hat natürlich das gleiche Problem wie die for(())Lösung, da es an Bash und sogar an eine bestimmte Version gebunden ist (wenn dies für Sie von Bedeutung ist).

David Gardner
quelle
14

Probieren Sie die bashintegrierte Hilfe aus:


$ 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
quelle
5
#! /bin/bash

function do_something {
   echo value=${1}
}

MAX=4
for (( i=0; i<MAX; i++ )) ; {
   do_something ${i}
}

Hier ist ein Beispiel, das auch in älteren Shells funktionieren kann und dennoch für große Mengen effizient ist:

Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'

Aber viel Glück beim Ausführen nützlicher Dinge in awk: Wie verwende ich Shell-Variablen in einem awk-Skript?

Brent Bradburn
quelle
2
Ich habe es vorher nicht bemerkt, aber eine ähnliche Syntax ist in einer der früheren Antworten gezeigt. Das Einzigartige hier ist die Verwendung von geschweiften Klammern anstelle des typischen do/ donePaares.
Brent Bradburn
4

Ich verwende normalerweise gerne eine leichte Variante des Standards für die Schleife. Ich verwende dies oft, um einen Befehl auf einer Reihe von Remote-Hosts auszuführen. Ich nutze die Klammererweiterung von bash, um for-Schleifen zu erstellen, mit denen ich nicht numerische for-Schleifen erstellen kann.

Beispiel:

Ich möchte den Befehl uptime auf den Frontend-Hosts 1-5 und den Backend-Hosts 1-3 ausführen:

% for host in {frontend{1..5},backend{1..3}}.mycompany.com
    do ssh $host "echo -n $host; uptime"
  done

Ich führe dies normalerweise als einzeiliger Befehl mit Semikolons an den Zeilenenden anstelle der oben besser lesbaren Version aus. Die wichtigsten Überlegungen zur Verwendung sind, dass Sie in geschweiften Klammern mehrere Werte angeben können, die in eine Zeichenfolge eingefügt werden sollen (z. B. pre {foo, bar} post führt zu prefoopost, prebarpost), und das Zählen / die Sequenzen mithilfe der doppelten Punkte ermöglichen können (Sie können a verwenden. .z usw.). Die Double-Period-Syntax ist jedoch eine neue Funktion von Bash 3.0. frühere Versionen unterstützen dies nicht.

terson
quelle
Was ist, wenn $ host var aus Versehen eine leere Zeile ist? Es würde immer noch ssh feuern. Wie vermeide ich das? In meinem Fall mache ich etwas anderes und Ihre Antwort wird mir helfen. Ich versuche, Google Mail auf neue Nachrichten zu überprüfen und, falls gefunden, eine SMS von und Betreff zu senden. Meine Frage trägt die Bezeichnung "Verbinden von zwei Bash-Befehlen", wenn Sie sie lesen möchten.
Volomike
Ich glaube nicht, dass Sie eine leere $ host-Variable bekommen würden. Dies liegt daran, dass im obigen Beispiel die Klammererweiterung verwendet wird. Die for-Schleife setzt die Variable $ host explizit auf Werte: frontend1.mycompany.com frontend2.mycompany.com. . backend1.mycompany.com Aber wenn Sie einen Weg sehen, einen Nullwert zu haben; Es würde mich interessieren zu wissen. Sie können das ssh in einem bedingten Test ausführen, wenn dies ein Problem darstellt.
Terson
1

Wenn Sie nur in bash interessiert sind, ist die oben vorgestellte "for ((...))" - Lösung die beste. Wenn Sie jedoch eine POSIX SH-konforme Lösung wünschen, die auf allen Unices funktioniert, müssen Sie "expr" und verwenden "while", und das liegt daran, dass "(())" oder "seq" oder "i = i + 1" unter verschiedenen Shells nicht so portabel sind


quelle
0

Ich benutze ständig Variationen davon, um Dateien zu verarbeiten ...

für Dateien in * .log; do echo "Mach Sachen mit: $ files"; echo "Mach mehr mit: $ files"; getan;

Wenn Sie an der Verarbeitung von Dateilisten interessiert sind, suchen Sie in der Option -execdir nach Dateien .


quelle
Ich denke du meinst -execdir Option zum Finden
Bis auf weiteres angehalten.