Einige Leute haben die falsche Vorstellung, dass reades der Befehl ist, eine Zeile zu lesen. Es ist nicht.
readLiest Wörter aus einer (möglicherweise mit Backslash fortgesetzten) Zeile, in der Wörter durch $IFSTrennzeichen getrennt sind und Backslash verwendet werden kann, um die Trennzeichen zu umgehen (oder Zeilen fortzusetzen).
Die generische Syntax lautet:
read word1 word2... remaining_words
readstdin liest ein Byte zu einer Zeit , bis er eine unescaped Zeilenende- Zeichen (oder End-of-Eingang) findet, aufteilt , dass das Ergebnis dieser Aufteilung in zu komplexen Regeln und speichert nach $word1, $word2... $remaining_words.
Zum Beispiel bei einer Eingabe wie:
<tab> foo bar\ baz bl\ah blah\
whatever whatever
und mit dem Standardwert $IFS, read a b cwürde zuweisen:
$a ⇐ foo
$b ⇐ bar baz
$c ⇐ blah blahwhatever whatever
Nun, wenn nur ein Argument übergeben wird, wird das nicht read line. Es ist immer noch so read remaining_words. Die Verarbeitung von umgekehrten Schrägstrichen wird weiterhin durchgeführt. IFS-Leerzeichen werden weiterhin am Anfang und am Ende entfernt.
Die -rOption entfernt die Backslash-Verarbeitung. Also würde derselbe Befehl wie oben mit -rvergeben
$a ⇐ foo
$b ⇐ bar\
$c ⇐ baz bl\ah blah\
Für den aufteilenden Teil ist es wichtig zu $IFSwissen, dass es zwei Klassen von Zeichen gibt : die IFS-Whitespace-Zeichen (nämlich Leerzeichen und Tabulatoren (und Zeilenumbrüche, obwohl dies hier keine Rolle spielt, wenn Sie -d verwenden), die ebenfalls vorkommen im Standardwert von $IFS) und den anderen sein. Die Behandlung dieser beiden Charakterklassen ist unterschiedlich.
Mit IFS=:( :wobei keine IFS Leerzeichen), wie ein Eingang :foo::bar::in aufgeteilt werden würde "", "foo", "", barund ""(und eine extra ""mit einigen Implementierungen obwohl das nicht mit Ausnahme keine Rolle read -a). Wenn wir dies durch :Leerzeichen ersetzen, erfolgt die Aufteilung nur in foound bar. Das heißt, führende und nachfolgende werden ignoriert, und Sequenzen von ihnen werden wie eine behandelt. Es gibt zusätzliche Regeln, wenn Leerzeichen und Nicht-Leerzeichen kombiniert werden $IFS. Einige Implementierungen können die Sonderbehandlung durch Verdoppeln der Zeichen in IFS ( IFS=::oder IFS=' ') hinzufügen / entfernen .
Wenn wir also nicht möchten, dass die führenden und nachfolgenden Leerzeichen ohne Leerzeichen entfernt werden, müssen wir diese IFS-Leerzeichen aus IFS entfernen.
Selbst bei IFS-Zeichen ohne Leerzeichen wird diese Eingabe durchgeführt, wenn die Eingabezeile eines (und nur eines) dieser Zeichen enthält und es sich um das letzte Zeichen in der Zeile handelt (wie IFS=: read -r wordbei einer Eingabe wie foo:), die POSIX-Shells enthält (nicht zshoder in einigen pdkshVersionen) gilt als eine betrachtet fooin diesen Schalen , weil Wort, die Zeichen $IFSwerden als als Terminatoren , so wordenthalten foo, nicht foo:.
Der kanonische Weg, eine Eingabezeile mit dem readeingebauten Code zu lesen, ist:
IFS= read -r line
(Beachten Sie, dass dies bei den meisten readImplementierungen nur für Textzeilen funktioniert, da das NUL-Zeichen nur in unterstützt wird. zsh)
Durch var=value cmddie Verwendung der Syntax wird sichergestellt, dass IFSnur für die Dauer dieses cmdBefehls ein anderer Wert festgelegt wird.
Geschichtsnotiz
Das readBuiltin wurde von der Bourne-Shell eingeführt und sollte schon Worte , keine Zeilen lesen . Es gibt einige wichtige Unterschiede zu modernen POSIX-Shells.
Die Bourne-Shell readunterstützt keine -rOption (die von der Korn-Shell eingeführt wurde), daher gibt es keine Möglichkeit, die Backslash-Verarbeitung zu deaktivieren, außer die Eingabe mit so etwas wie dieser sed 's/\\/&&/g'vorzuverarbeiten.
Die Bourne-Shell hatte nicht die Vorstellung von zwei Klassen von Zeichen (die wiederum von ksh eingeführt wurde). In der Bourne - Shell alle Zeichen der gleichen Behandlung unterzogen werden, wie IFS Leerzeichen in KSH tun, ist , dass IFS=: read a b cauf einem Eingangs wie foo::barzuweisen würde , barum $bnicht den leeren String.
In der Bourne-Shell mit:
var=value cmd
Wenn cmdes ein eingebautes ist (wie es readist), varbleibt es auf eingestellt, valuenachdem cmdes fertig ist. Das ist besonders kritisch, $IFSda in der Bourne-Shell $IFSalles aufgeteilt wird, nicht nur die Erweiterungen. Wenn Sie das Leerzeichen $IFSin der Bourne-Shell entfernen , "$@"funktioniert dies ebenfalls nicht mehr.
In der Bourne-Shell führt das Umleiten eines zusammengesetzten Befehls dazu, dass dieser in einer Subshell ausgeführt wird (in den frühesten Versionen funktionierten sogar Dinge wie read var < fileoder exec 3< file; read var <&3funktionierten nicht). In der Bourne-Shell war es daher selten, readetwas anderes als Benutzereingaben auf dem Terminal zu verwenden (wo diese Zeilenfortsetzungsbehandlung Sinn machte)
Einige Unices (wie HP / UX, es gibt auch einen in util-linux) haben noch einen lineBefehl zum Lesen einer Eingabezeile (der bis zur Single UNIX Specification Version 2 ein Standard-UNIX-Befehl war ).
Das ist im Grunde dasselbe, mit der head -n 1Ausnahme, dass jeweils ein Byte gelesen wird, um sicherzustellen, dass nicht mehr als eine Zeile gelesen wird. Auf diesen Systemen können Sie Folgendes ausführen:
line=`line`
Das bedeutet natürlich, einen neuen Prozess zu erzeugen, einen Befehl auszuführen und seine Ausgabe über eine Pipe zu lesen IFS= read -r line, was viel weniger effizient ist als die von ksh , aber dennoch viel intuitiver.