Ich hatte immer gedacht, dass Shells ganze Skripte analysieren, einen AST erstellen und diesen AST dann aus dem Speicher ausführen. Ich habe jedoch gerade einen Kommentar von Stéphane Chazelas gelesen und die Ausführung dieses Skripts getestet: edit-while-executing.sh:
#!/bin/bash
echo start
sleep 10
und dann, während es beim Laufen schlief:
$ echo "echo end" >> edit-while-executing.sh
und es hat funktioniert, damit es am Ende "Ende" druckt.
Wenn Sie jedoch versuchen, dies zu ändern:
#!/bin/bash
while true; do
echo yes
done
indem Sie tun:
$ printf "%s" "no " | dd of=edit-while-executing.sh conv=notrunc seek=35 bs=1
Es hat nicht funktioniert und immer wieder "Ja" gedruckt.
Ich habe mich auch gefragt, ob andere Nicht-Shell-Interpreter auch so funktionieren, und habe das Äquivalent des ersten Skripts mit Python ausprobiert, aber es hat nicht funktioniert. Vielleicht ist Python kein Interpreter mehr und eher ein JIT-Compiler.
Um meine Frage zu wiederholen: Ist dies ein Verhalten, das für Muscheln allgegenwärtig und auf sie beschränkt ist oder auch bei anderen Dolmetschern (die nicht als Muscheln angesehen werden) vorhanden ist? Wie funktioniert das auch so, dass ich die erste Änderung vornehmen kann, aber nicht die zweite?
for
Schleife) analysiert , sodass die Änderung an der Datei des Shell-Skripts keine Auswirkungen hatte.. myscript
wird also zuerstmyscript
als eine zusammengesetzte Anweisung analysiert und dann ausgeführt. Dies ist beispielsweise ein Grund, warum in einem solchen Skript definierte Aliase im Skript noch nicht aktiv sind.Antworten:
Dies läuft also auf unbestimmte Zeit in Bash / dash / ksh / zsh (oder zumindest bis Ihre Festplatte voll ist):
Das , was zu beachten ist, dass nur Sachen
hängtenzur Skriptdatei nach der letzten Zeile hinzugefügt die Shell - Angelegenheiten gelesen hat. Die Shells gehen nicht zurück, um die früheren Teile erneut zu lesen, was sie selbst nicht tun könnten, wenn die Eingabe eine Pipe wäre.Das ähnliche Konstrukt funktioniert in Perl nicht, es liest die gesamte Datei ein, bevor es ausgeführt wird.
Wir können sehen, dass dies auch bei Eingabe über eine Pipe der Fall ist. Dies gibt nach 1 Sekunde einen Syntaxfehler (und nur diesen):
Während dasselbe Skript z. B. an Bash weitergeleitet wird,
hello
wird eine Sekunde später der Syntaxfehler gedruckt und ausgelöst.Python ähnelt Perl mit Piped-Eingabe, obwohl der Interpreter interaktiv eine Lese-Auswertungs-Druckschleife ausführt.
Zusätzlich zum zeilenweisen Lesen des Eingabeskripts werden mindestens Bash- und Dash-Prozessargumente
eval
zeilenweise verarbeitet:Zsh und ksh geben den Fehler sofort aus.
In ähnlicher Weise wird Zsh bei Skripts mit Sourcing-Funktion ebenso wie Bash und Dash zeilenweise ausgeführt:
quelle
perl -e 'if(fork()){exec qw/sh/}else{while(1){sleep 1;sysseek STDIN,0,0}}' < foo.sh
Diese Funktion ist in anderen Interpreten vorhanden, die das anbieten, was als a bezeichnet wird
read
eval
print
loop
. LISP ist eine ziemlich alte Sprache mit einer solchen Funktion, und Common LISP verfügt über eineread
Funktion, die hier den Ausdruck einliest,(+ 2 2)
der danneval
zur Auswertung übergeben werden kann (obwohl Sie dies in echtem Code aus verschiedenen Sicherheitsgründen möglicherweise nicht auf diese Weise tun möchten ):Wir können auch unsere eigene sehr einfache REPL definieren, ohne viel an Funktionen oder Debugging oder so ziemlich allem anderen, aber dies zeigt die REPL-Teile:
Grundsätzlich werden, wie auf dem Typenschild angegeben, Daten eingelesen, ausgewertet, gedruckt und dann (vorausgesetzt, es stürzt nichts ab und es gibt immer noch Strom oder etwas, das das Gerät mit Strom versorgt) wieder zum Lesevorgang zurückgeschaltet. Es ist nicht erforderlich, im Voraus einen AST aufzubauen. (SBCL benötigt die
force-output
undfresh-line
Ergänzungen aus Anzeigegründen, andere Common LISP-Implementierungen können oder können nicht.)Andere Dinge mit REPL sind TCL ("eine von einem radioaktiven LISP gebissene Hülle"), die Grafikmaterial mit Tk enthält
Oder FORTH hier, um eine Funktion
f>c
für die Temperaturumwandlung zu definieren (die "ok" werden hinzugefügt durchgforth
):quelle
tclsh < file
/expect < file
(nichttclsh file
/expect file
).Mindestens eine Muschel, Fisch, zeigt dieses Verhalten nicht (aber Fisch ist auf andere Weise ungewöhnlich):
(Eine frühere Version dieser Antwort hatte falsche Beobachtungen von Python und Ruby gemacht.)
quelle