Warum funktioniert dies beim Lesen in einem Terminal, jedoch nicht in einem Shell-Skript?

8

Ich bin auf dieses interessante Problem gestoßen, als ich meine WM-Leiste mit Infotext gefüllt habe, der durch Festlegen des Titels des Stammfensters angewendet wird, d. H. xsetroot -name "clever words"

Zu diesem Zweck funktioniert das Drucken eines Vermögens in einem Terminal einwandfrei:

fortune -s | while read -r; do xsetroot -name "$REPLY"; done

Dasselbe schlägt jedoch fehl, wenn es von einem Shell-Skript ausgeführt wird:

#!/bin/sh
cat /tmp/afile | while read; do echo "$REPLY"; done

Produziert:

$ sh afilereader
afilereader: 2: read: arg count

Dies wird natürlich behoben, indem wir unser Vermögensergebnis einer Variablen zuweisen und dann xsetroot mit dieser Variablen verwenden. Aber ich würde immer noch gerne verstehen, warum dies in einem Skript nicht funktioniert.

Ich erkenne, dass jeder Befehl auf beiden Seiten der Pipeline in einer eigenen Subshell ausgeführt wird, sehe jedoch nicht, wie sich ihre lokalisierten Variablen auf die while-Leseschleife auswirken können. Oder liegen Variablen auch zwischen den Schleifeniterationen außerhalb des Gültigkeitsbereichs?

Was vermisse ich?

Update: Das von shmir verwendete ist mit einem Dash verknüpft, der gerade POSIX-konform gemacht wird. Mit dem ehrwürdigeren bashlöste dies.

umkehren
quelle
1
Das Verhalten von dash zeigt hier keinen Mangel an POSIX-Konformität. POSIX erfordert nicht, dass das readohne eine Variable aufgerufen werden kann: pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html
dubiousjim

Antworten:

10

Sie scheinen das erste Beispiel in bashund das zweite in /bin/sheiner POSIX-Shell auszuführen, auf die ein Argument übergeben werden muss, das die Variable angibt, in die Sie die Eingabe eingeben möchten. Das Ändern des Shebang in #!/bin/bashsollte dies beheben.

Chris Down
quelle
Gute Beobachtung @Chris! Das funktioniert. Ich denke, ich werde etwas über den Unterschied zwischen shund nachlesen bash.
invertieren
In der Tat ungewöhnlich! Ich könnte mich wieder /bin/shmit Bash verbinden, aber ich denke, ich würde Bash von nun an direkt verwenden, um Mehrdeutigkeiten zu vermeiden. Danke :)
invertieren
Häufig unterscheiden sich interaktive Shells von Shell-Skripten in der Pufferung ihrer Ausgabe. Das Lesen aus Interprozess-Pipes kann zu allen möglichen seltsamen Timing-Verhaltensweisen führen, wenn der Befehl, der die Ausgabe generiert, seine Schreibvorgänge puffert, wenn er nicht interaktiv ausgeführt wird.
JesseM
5

In sh-Syntax benötigen Sie

IFS= read -r REPLY

Einige Shells wie ksh, bash und zsh können readohne Variablennamen aufgerufen werden, aber das Verhalten unterscheidet sich zwischen ihnen. Siehe zum Beispiel die Ausgabe von

printf 'te\ st\\\na ' | "$shell" -c 'read; printf "%s\n" "<$REPLY>"'

unterscheidet sich bei allen bash, zsh, pdksh und ksh93

Stéphane Chazelas
quelle
Das macht Sinn, warum die Shell, die ich verwendet habe, den Variablennamen nicht kannte, danke @Stephane.
invertieren