Bash-For-Loop ohne In-Foo-Bar-Teil

25

Ich habe mir kürzlich einen Code angesehen, der mich verwirrt hat, weil er funktioniert und ich nicht damit gerechnet habe. Der Code reduziert sich auf dieses Beispiel

#!/bin/bash
for var;
do
  echo "$var"
done

Wenn mit Kommandozeilenargumenten ausgeführt wird, werden diese gedruckt

$ ./test a b c
a
b
c

Das ist (für mich) unerwartet. Warum führt dies nicht zu einem Fehler, da varundefiniert? Wird diese Vorgehensweise als "gute Praxis" angesehen?

user270650
quelle

Antworten:

27

forloops Durchlaufen der Positionsparameter, wenn in value1 value2...in allen Bourne-ähnlichen Shells kein Teil angegeben ist.

Dies war bereits in der Bourne-Shell aus den späten 70ern der Fall, obwohl Sie dies in der Bourne-Shell weglassen müssen ;(Sie können dies auch verwenden for i do(außer in einigen alten Ash-Versionen, in denen Sie vor dem eine neue Zeile benötigen do)).

Siehe Was ist der Zweck des Schlüsselworts "do" in Bash for loops? Weitere Informationen, einschließlich überraschender Varianten.

Tun:

for i
do
  something with "$i"
done

ist eine gute Übung. Es ist etwas portabler / zuverlässiger als das normalerweise Äquivalent:

for i in "$@"; do
  something with "$i"
done

Bei der Bourne-Shell hat ksh88 unter bestimmten Bedingungen einige Probleme (z. B. wenn $#in einigen Versionen der Bourne-Shell 0 ist (was ${1+"$@"}nicht "$@"funktioniert) oder wenn $IFSdas Leerzeichen in Bourne und ksh88 nicht enthalten ist) oder wann Die nounsetOption ist aktiviert und $#ist in einigen Versionen einiger Shells einschließlich 0 bash( wieder mit ${1+"$@"}als Workaround ).

Stéphane Chazelas
quelle
Musste das dreimal lesen, bevor mein Gehirn beschloss, die wiederholte Schleife zu Beginn nicht mehr zu bearbeiten
Three Diag,
20

Dies ist das Standardverhalten, ja. Es ist im helpdes forSchlüsselworts dokumentiert :

terdon@tpad ~ $ help for
for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.

    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.

    Exit Status:
    Returns the status of the last command executed.

Also, wenn Sie es nicht , eine Liste zu iterieren übergeben, wird es zu iterieren Standard $@, wobei die Anordnung von Positionsparametern ( a, bund cin Ihrem Beispiel).

Und dieses Verhalten wird von POSIX definiert, also wird es, soweit dies möglich ist, als "gute Praxis" angesehen.

terdon
quelle