Warum ist es ' nicht möglich, mit „read“ von „stdin“ zu lesen, wenn ein Skript an bash weitergeleitet wird?

Ich suche keine Problemumgehungen oder Lösungen für das Problem. Ich bin damit einverstanden, dass es in . Ich verstehe einfach nicht, warum es nicht funktioniert.

Ich suche nach einer ausführlichen Antwort, warum das folgende Skript nicht funktioniert. Alle vorherigen Internet-Suchergebnisse, einschließlich der Beiträge von unix.stackexchange.com, konnten dies nicht vollständig klären. Dies hat etwas mit dem Lesen von read aus was nicht funktioniert, weil stdin bereits von cat Feeding über die Pipe?

Beispiel für ein Bash-Skript test.sh:

echo "Please say name:" read NAME echo "Hello $NAME" 

Methode 1 ruft das Skript mit bash test.sh auf:

$ bash test.sh Please say name: XYZ Hello XYZ $ 

Methode 2 führt das Skript über Piping to aus bash:

$ cat test.sh | bash Please say name: $ 

Das Skript kehrt also sofort zur Eingabeaufforderung zurück, ohne auf Eingaben zu warten oder die zweite zu drucken Zeile.

Kommentare

  • Es wurde auf die Eingabe echo "Hello $NAME" gewartet und diese empfangen und dann beendet.

Antwort

Sie hat mit read von stdin gelesen, aber was Sie gelesen haben, war die nächste Zeile der Standardeingabe – nämlich echo "Hello $NAME". Nach dem Lesen dieser Zeile gab es keine Eingabe mehr und daher keine weiteren auszuführenden Befehle, und das Skript war beendet.

Es gibt nur einen Standardeingabestream, und Sie sind Dies entspricht der Verwendung einer interaktiven bash -Sitzung zum Lesen von Befehlen aus Ihrer Eingabe sowie von read Antworten sowie alle anderen Befehle, für die Sie die Standardeingabe verwenden möchten.

Sie können dies sehen, wenn Sie am Ende des Skripts eine zusätzliche Zeile einfügen:

echo "Please say name:" read NAME echo "Hello $NAME" printf "name=%s\n" "$NAME" 

Dies bietet einen weiteren Befehl, um die Ausführung des Skripts fortzusetzen, und zeigt uns, was in NAME eingelesen wurde:

Please say name: name=echo "Hello $NAME" 

Sie können sehen, dass die Variable wörtlich enthält, was in der Skriptdatei geschrieben wurde – es wurde keine Variableninterpolation, -ausführung oder -erweiterung durchgeführt.


Wenn Sie read vom Terminal aus verwenden möchten, ist dies möglich Der einfachste Weg, der wahrscheinlich funktioniert, ist das Lesen von der Standardausgabe anstelle der Standardeingabe (!), die vermutlich mit dem TTY verbunden ist:

read NAME <&1 

Dies Ich werde warten, bis ich etwas eingebe, und dann mit dem Rest des Programms fortfahren. Sie können auch /dev/tty oder $(tty) verwenden.

Kommentare

  • read var </dev/tty wäre wohl besser, als anzunehmen, dass stdout mit dem Contrilling tty verbunden ist.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.