Das scheint zu funktionieren:
#!/bin/sh
pressed_ctrl_c=
trap "pressed_ctrl_c=1" INT
while true
do
(trap "" INT; foo)&
wait || wait
if [ "$pressed_ctrl_c" ]
then
# echo
break
fi
done
- Auf
pressed_ctrl_c
null initialisieren . Dies ist in einem Skript wahrscheinlich nicht erforderlich.
trap command signum
Weist die Shell an, die Signalnummer abzufangen signum
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 Shell pressed_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.)
- Innerhalb der Schleife haben wir eine Befehlszeile in Klammern. Dadurch wird eine Unterschale erstellt.
- Wir verwenden den
trap
Befehl erneut. Diese Zeit command
ist eine Nullzeichenfolge. Dies weist die Shell an, die Signalnummer zu ignorieren signum
. Da dies in Klammern steht, betrifft es nur die Unterschale.
- Ausführen
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
.
- Stellen Sie die Unterschale in den Hintergrund….
- … Und warten Sie, bis es fertig ist.
- Wenn der
wait
Befehl erfolgreich ist, fahren Sie mit der if
Anweisung fort. Wenn dies fehlschlägt, führen Sie einen anderen aus. (Ich werde darauf zurückkommen.)
- Wenn
$pressed_ctrl_c
eingestellt, aus der Schleife ausbrechen. Kommentieren Sie optional den echo
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). Der wait
Befehl wird erfolgreich beendet, wenn die Subshell beendet wird. dh wenn der foo
Befehl beendet wird. (Der wait
Befehl wird erfolgreich beendet, auch wenn foo
ein Fehler zurückgegeben wird.) Wenn der erste wait
Befehl erfolgreich beendet wird, überspringen wir den zweiten und gehen zum if
.
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 Shell pressed_ctrl_c
auf 1 gesetzt und der (erste) wait
Befehl abgebrochen . Da der erste wait
Befehl fehlgeschlagen ist, fahren wir mit dem zweiten fort. Denken Sie daran, dass die foo
Subshell noch ausgeführt wird, sodass dies wait
noch etwas zu tun hat (dh es wird gewartet , bis die Subshell foo
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 es foo
im Hintergrund ausgeführt wird. Sie können dies abmildern, indem Sie sagen wait || 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 Sie foo
von der Tastatur lesen, muss das oben genannte überarbeitet werden.