Angenommen, ich habe ein Bash-Skript, das Folgendes tut:
while :
do
foo
done
Ich möchte in der Lage sein, dieses Skript von der Konsole aus auszuführen und es zu einem beliebigen Zeitpunkt zu beenden, solange es zwischen zwei foo-Läufen auftritt. Wenn ich also beispielsweise Ctrl+ drücke C(es könnte eine andere Aktion sein, die das Beenden des Skripts bewirkt, Ctrl+ Cist nur ein Beispiel), wird dies am nächsten verfügbaren Punkt beendet, nachdem foo ausgeführt wurde:
while :
do
foo
if [pressed_ctrl_c]:
break
done
Antworten:
Sie könnten diese Art von Konstrukt ausprobieren:
Einige Notizen
read
undtest
-Paar demonstriert die interaktive Steuerung des geschützten Codesegments innerhalb des( ... )
Blocks.exit 90
ist das Äquivalent vonbreak
aber aus einer Unterschale heraus. Dietest 0 != $? ...
Zeile unmittelbar nach dem Ende des Unterschalenblocks dient dazu, denexit 90
Status zu erfassen und das zu implementierenbreak
, was der Code tatsächlich wollte.break
,exit
, etc ...)gdb
einen eigenen Handler fürSIGINT
( CtrlC). Wenn das Ziel darin besteht, zu verhindern, dass ein Benutzer aus der Sitzung ausbricht, kann das Ändern der Interrupt-Taste dazu beitragen, die Situation zu verschleiern (siehe den folgenden Code). Unelegant, aber potenziell wirksam.Ändern der SIGINT-Taste am Terminal
quelle
foo
vollständig ausgeführt werden soll, nicht erfüllt , selbst wenn <Strg> + <C> eingegeben wurde.source
nicht auf normale Weise aufzurufen . Ich denke, Sie werden feststellen, dass <Strg> + <C> keine Wirkung hat. Ich kann es nicht erklären (können Sie?) Freundlicher Vorschlag: Ändern Sie Ihreexit 0
in(exit 0)
(oder einfachtrue
), oder dies führt dazu, dass Ihre interaktive Shell beendet wird. ……… Übrigens, als Sie „exit 1
Status erfassen “ sagten, meinten Sie „…exit 90
Status“?source
, vor allem, weil Sie, wenn Sie versuchen, Dingetrap
direkt in der Befehlszeile zu erledigen, alle leicht in Knoten geraten können. Vielen Dank fürexit 1
- ich dachte, ich hätte sie alle gefangen, als ich zu wechselte90
(ich hatte das Gefühl, dass dieser neue Wert als Fluchtkriterium "offensichtlicher" war).(trap "pressed_ctrl_c=1" INT; while true …)
. …Das scheint zu funktionieren:
pressed_ctrl_c
null initialisieren . Dies ist in einem Skript wahrscheinlich nicht erforderlich.trap command signum
Weist die Shell an, die Signalnummer abzufangensignum
und auszuführen,command
wenn sie eine abfängt. "INT" steht für "SIGINT", was für "Interrupt Signal" steht. Dies ist der Fachbegriff für das von Ctrl+ erzeugte Signal. CWenn Sie also Ctrl+ eingeben C, wird die Shellpressed_ctrl_c
auf 1 gesetzt. (SIGINT hat einen numerischen Wert von 2, so können Sie sagen,trap "pressed_ctrl_c=1" 2
ob Sie beim Tippen sparen möchten.)trap
Befehl erneut. Diese Zeitcommand
ist eine Nullzeichenfolge. Dies weist die Shell an, die Signalnummer zu ignorierensignum
. Da dies in Klammern steht, betrifft es nur die Unterschale.foo
. Da es von der Subshell ausgeführt wurde,foo
wird Ctrl+ ignoriert C, dh es wird auch dann weiter ausgeführt, wenn Sie es eingeben .wait
Befehl erfolgreich ist, fahren Sie mit derif
Anweisung fort. Wenn dies fehlschlägt, führen Sie einen anderen aus. (Ich werde darauf zurückkommen.)$pressed_ctrl_c
eingestellt, aus der Schleife ausbrechen. Kommentieren Sie optional denecho
Befehl aus, wenn Ctrl+ Cauf Ihrem Terminal als angezeigt wird^C
und Sie zur nächsten Zeile wechseln möchten.Wir führen einen Befehl im Hintergrund aus und dann sofort
wait
dafür. Dies ist dem Ausführen des Befehls im Vordergrund sehr ähnlich (zumindest wenn dies in einem Skript ausgeführt wird). Derwait
Befehl wird erfolgreich beendet, wenn die Subshell beendet wird. dh wenn derfoo
Befehl beendet wird. (Derwait
Befehl wird erfolgreich beendet, auch wennfoo
ein Fehler zurückgegeben wird.) Wenn der erstewait
Befehl erfolgreich beendet wird, überspringen wir den zweiten und gehen zumif
.Die Shell, die die Schleife ausführt, fängt Interrupts ab, aber die Subshell und damit der
foo
Prozess ignorieren sie. Wenn Sie also Ctrl+ eingeben C, wird die Shellpressed_ctrl_c
auf 1 gesetzt und der (erste)wait
Befehl abgebrochen . Da der erstewait
Befehl fehlgeschlagen ist, fahren wir mit dem zweiten fort. Denken Sie daran, dass diefoo
Subshell noch ausgeführt wird, sodass dieswait
noch etwas zu tun hat (dh es wird gewartet , bis die Subshellfoo
fertig ist.)Wenn die Variable so eingestellt wurde, dass angezeigt wird, dass während der Ausführung ein Ctrl+ Cgedrückt
foo
wurde, wird die Schleife unterbrochen.Wenn Sie zweimal Ctrl+ drücken C, unterbricht der zweite den zweiten
wait
Befehl und bricht ihn ab . Dadurch wird Ihr Skript beendet und Sie kehren zu Ihrer Shell-Eingabeaufforderung zurück, während esfoo
im Hintergrund ausgeführt wird. Sie können dies abmildern, indem Sie sagenwait || wait || wait || wait
: Erweitern Sie es so weit wie Sie möchten. Sie müssten jeweils Ctrl+ Ceinmal eingeben,wait
um das Skript vorzeitig zu beenden.D'oh!
Ein Problem dabei ist, dass für Prozesse, die von einem Skript in den Hintergrund gestellt werden, die Standardeingabe auf gesetzt ist
/dev/null
. Wenn Siefoo
von der Tastatur lesen, muss das oben genannte überarbeitet werden.quelle