Erwägen Sie eine benutzerdefinierte Befehlszeilensoftware (z. B. loopHelloWorld), die Strg+C für ein reibungsloses Herunterfahren erkennt. Wie kann ich die Antwort weiterleiten, ohne sie zu verlieren Ctrl+C
?
$ loopHelloWorld
- Ctrl+C to nicely shutdown
Aber mit Pipe beendet die Pipe die Software ohne ordentliches Herunterfahren
$ loopHelloWorld |
while IFS= read -r line; do
echo "$line"
done
Beispiel
ping example.com |
while IFS= read -r line; do
echo "$line"
done
Antwort1
Ctrl+Cbewirkt, dass ein SIGINT an alle Prozesse in der Pipeline gesendet wird (da sie alle in derselben Prozessgruppe ausgeführt werden, die diesem Vordergrundjob Ihrer interaktiven Shell entspricht).
Also rein:
loopHelloWorld |
while IFS= read -r line; do
echo "$line"
done
Sowohl der laufende Prozess loopHelloWorld
als auch der Prozess, der die Subshell ausführt, die die while
Schleife ausführt, erhalten die SIGINT
.
Wenn loopHelloWorld
die Ctrl+C to nicely shutdown
Nachricht auf die Standardausgabe geschrieben wird, wird sie auch in die Pipe geschrieben. Wenn dasnachdie Unterschale am anderen Ende ist bereits gestorben, dann loopHelloWorld
wirdAuchErhalten Sie eine SIGPIPE, die Sie handhaben müssen.
Hier sollten Sie diese Meldung an stderr schreiben, da es sich nicht um die normale Ausgabe Ihres Befehls handelt (trifft ping
jedoch nicht auf das Beispiel zu). Dann würde sie nicht durch die Pipe gehen.
loopHelloWorld
Oder Sie könnten die Subshell, die die While-Schleife ausführt, so einrichten, dass sie das SIGINT ignoriert, sodass sie die Ausgabe nach dem SIGINT weiterliest :
loopHelloWorld | (
trap '' INT
while IFS= read -r line; do
printf '%s\n' "$line"
done
)
Dies würde jedoch dazu führen, dass der Beendigungsstatus der Pipeline 0 ist, wenn Sie drücken Ctrl+C.
Eine weitere Option für dieses spezielle Beispiel wäre die Verwendung von zsh
oder ksh93
anstelle von bash
. In diesen Shells while
würde die Schleife im Hauptprozess der Shell ausgeführt und wäre daher nicht von SIGINT betroffen.
loopHelloWorld | cat
Das würde allerdings nicht helfen, wenn die Prozessgruppe im Vordergrund ausgeführt wird cat
.loopHelloWorld
Antwort2
Verwenden Sie eine Falle:
#! /bin/bash
trap handleInt SIGINT
interrupted=0
function handleInt {
echo "Interrupted..."
interrupted=1
}
while true
do
[[ interrupted -ne 0 ]] && { echo "Ctrl-C caught, exiting..." ; exit ; }
echo "Sleeping..."
sleep 1
read -r line
echo "$line"
done