Verwenden von "while read ..." in einem Linux-Skript

34

Könnte jemand erklären, wie der folgende Code funktioniert?

echo '1 2 3 4 5 6' | while read a b c
do
  echo $c $b $a
done

Insbesondere möchte ich wissen, warum die Ausgabe dieser Schleife 3 4 5 6 2 1statt 3 2 1und 6 5 4in zwei separaten Zeilen erfolgt? Ich kann mich nicht darum kümmern ...

linuxgringo
quelle

Antworten:

41

readLiest eine ganze Zeile aus der Standardeingabe, teilt die Zeile in Felder auf und weist diese Felder den angegebenen Variablen zu. Wenn es mehr Teile als Variablen gibt, werden die verbleibenden Teile der letzten Variablen zugewiesen.

In Ihrem Fall $aist zugewiesen 1, $bzugewiesen 2und $cder Rest 3 4 5 6.

Florian Diesch
quelle
Vielen Dank Florian! Jetzt macht es Sinn ... Aus irgendeinem Grund dachte ich, Leerzeichen würden jede Variablenlesung begrenzen, aber anscheinend nicht. Ich schätze Ihre Hilfe!!
Linuxgringo
24

Wenn Sie die Schleife auf diese Weise umschreiben, sehen Sie, was gerade passiert:

echo '1 2 3 4 5 6' | while read a b c
  do
    echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
  done

Dies ergibt als Ausgabe:

(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)

Beachten Sie zuerst, dass nur ein einziger Echobefehl ausgeführt wird. Wenn es mehrmals ausgeführt würde, würden Sie unter anderem die (iteration beginning)und (iteration ending)Teilzeichenfolgen mehrmals gedruckt sehen.

Dies bedeutet, dass eine whileSchleife hier nicht wirklich etwas bewirkt. Die readeingebaute Funktion liest durch Leerzeichen getrennten Text 1 in jede angegebene Variable. Zusätzliche Eingaben werden an das Ende der zuletzt angegebenen Variablen angehängt. 2 Also Variablen aund bnehmen die Werte 1bzw. 2an, während cden Wert annimmt 3 4 5 6.

Wenn die Schleifenbedingung ( while read a b c) zum zweiten Mal ausgewertet wird, ist keine Eingabe mehr von der Pipe verfügbar (wir haben nur eine einzige Textzeile weitergeleitet), sodass der readBefehl mit false anstelle von true ausgewertet wird und die Schleife angehalten wird (bevor die Pipe ausgeführt wird) Körper ein zweites Mal).

1 : Um technisch und spezifisch zu sein, liest das readeingebaute Element , wenn Variablennamen als Argumente übergeben werden, die Eingabe und teilt sie in separate "Wörter" auf, wenn es auf IFS-Leerzeichen stößt (siehe auch diese Frage und diesen Artikel ).

2 : read‚s Verhalten keine zusätzlichen Bereichen Eingabe in die letzte Variable von Jamming spezifiziert viele scripters nicht intuitiv ist, auf den ersten. Es wird verständlicher, wenn man bedenkt, dass Florian Dieschs Antwort besagt , readdass er immer versucht, eine ganze Zeile zu lesen - und das readsoll sowohl mit als auch ohne Schleife verwendbar sein.

Eliah Kagan
quelle
Eliah, danke, dass du dir die Zeit genommen hast, alle Details zu erklären. Ich vermutete, dass whiledies in diesem Beispiel nicht dem normalen Zweck entsprach, aber dann readwarf mich der Befehl ab ... Irgendwie interpretierte ich es als "while read a b cis not false, do echo ...". Vielen Dank für die Erklärung, wie es wirklich funktioniert hat. Ich bin gestern auf diesen Code gestoßen und wusste, dass er mich
nerven
@linuxgringo Eigentlich ist der Schleifenkörper wird jedes Mal ausgeführt , read a b causgewertet wahr, und die Schleifenbedingung ( read a b c) läuft mehr als einmal. Bit wertet es nur das 1. Mal wahr aus . Das zweite Mal, gibt es keine Eingabe mehr aus der Leitung zu lesen, so das Ende der Datei angetroffen wird, verursacht readzurückzukehren falsch . (Weitere help readInformationen finden Sie im letzten Abschnitt der Ausgabe von "Exit Status". In Shell-Skripten bedeutet Null Wahr und Nicht-Null Falsch.) Wenn Sie mehr als eine Eingabezeile weiterleiten, while read ...wird der Schleifenkörper verwendet mehrmals ausgeführt werden.
Eliah Kagan