Capture SIGINT mit KeyboardInterrupt Ausnahme funktioniert im Terminal, nicht im Skript

8

Ich versuche, SIGINT (oder Tastatur-Interrupt) in Python 2.7 Programm zu fangen. So sieht mein Python-Testscript test aus:

%Vor%

Weiter Ich habe ein Shell-Skript test.sh :

%Vor%

Wenn ich das Skript mit bash, sh oder etwas bash test.sh ausführe, läuft der Python-Prozess test weiter und kann nicht mit SIGINT gekillt werden. Wenn ich den Befehl test.sh kopiere und ihn in (bash) terminal einfüge, wird der Python-Prozess test beendet.

Ich kann nicht verstehen, was vorgeht, was ich gerne verstehen würde. Also, wo ist der Unterschied und warum?

Hier geht es nicht um wie man SIGINT in Python fängt! Laut Dokumenten - das ist der Weg, der funktionieren sollte:

  

Python installiert standardmäßig eine kleine Anzahl von Signalhandlern: SIGPIPE ... und SIGINT wird in eine KeyboardInterrupt-Ausnahme übersetzt

Es fängt tatsächlich KeyboardInterrupt ein, wenn SIGINT von kill gesendet wird, wenn das Programm direkt von der Shell gestartet wird, aber wenn das Programm von bash script im Hintergrund gestartet wird, scheint KeyboardInterrupt niemals angehoben.

    
Velda 23.11.2016, 22:17
quelle

1 Antwort

14

Es gibt einen Fall, in dem der Standard-Sigint-Handler beim Start nicht installiert ist, und das ist, wenn die Signalmaske beim Programmstart SIG_IGN für SIGINT enthält. Der dafür zuständige Code kann hier gefunden werden.

Die Signalmaske für ignorierte Signale wird vom übergeordneten Prozess geerbt, während gehandhabte Signale auf SIG_DFL zurückgesetzt werden. Wenn also SIGINT ignoriert wurde, wird die Bedingung if (Handlers[SIGINT].func == DefaultHandler) in der Quelle nicht ausgelöst und der Standard-Handler wird nicht installiert. Python überschreibt in diesem Fall nicht die vom übergeordneten Prozess vorgenommenen Einstellungen.

Versuchen wir nun, den verwendeten Signal-Handler in verschiedenen Situationen zu zeigen:

%Vor%

Also wurde im letzten Beispiel SIGINT auf 1 gesetzt ( SIG_IGN ). Dies ist das gleiche wie beim Starten eines Hintergrundjobs in einem Shell-Skript, da diese standardmäßig nicht interaktiv sind (es sei denn, Sie verwenden die Option -i im Shebang).

Dies wird dadurch verursacht, dass die Shell das Signal ignoriert, wenn sie einen Hintergrundjob in einer nicht interaktiven Shell-Sitzung startet und nicht direkt mit Python. Mindestens bash und dash verhalten sich so, ich habe keine anderen Shells ausprobiert.

Es gibt zwei Möglichkeiten, mit dieser Situation umzugehen:

  • Installieren Sie den Standard-Signalhandler manuell:

    %Vor%
  • Fügen Sie dem shebang des Shell-Skripts die Option -i hinzu, z. B .:

    %Vor%

edit: Dieses Verhalten ist im bash-Handbuch dokumentiert:

  

SIGNALE
  ...
  Wenn die Jobsteuerung nicht wirksam ist, ignorieren asynchrone Befehle SIGINT und SIGQUIT zusätzlich zu diesen geerbten Handlern.

Dies gilt für nicht interaktive Shells, da die Jobsteuerung standardmäßig deaktiviert ist und tatsächlich in POSIX angegeben ist: Shell-Befehlssprache

    
mata 24.11.2016, 11:27
quelle

Tags und Links