2016-07-20 1 views
0

Ich möchte einen ziemlich lang laufenden Subprozess in Python starten, und möchte es mit ^C beenden können. Das Drücken von ^C führt jedoch dazu, dass das übergeordnete Objekt KeyboardInterrupt empfängt und beendet (und manchmal sleep als nicht mehr vorhandener Prozess verlässt).Target KeyboardInterrupt zu Subprozess

import subprocess 
subprocess.call("sleep 100".split()) 

Wie kann ich es so haben, dass ^C nur Drücken beendet den sleep Prozess (wie wir auf einer Shell-Befehlszeile haben würde), und lassen Sie die Eltern weitermachen? Ich glaube, ich habe versucht, einige Kombinationen von preexec_fn, start_new_session und shell Flags zu call, aber mit keinem Erfolg.

bearbeiten: Ich weiß, ich kann die subprocess Aufruf in einem try-catch Block wickeln, und ignorieren Sie die Tastatur-Interrupt; aber ich will das nicht tun. Meine Frage ist folgende: Der Tastatur-Interrupt hätte sleep töten sollen und hätte das Ende davon sein sollen. Warum wird dann sozusagen auf den Elternteil propagiert. Oder ist es wie der sleep Prozess war nie derjenige, der den Interrupt erhalten? Wenn nicht, wie würde ich es zum Vordergrundprozess machen?

Wieder versuche ich, die Eltern-Kind-Beziehung einer Befehlszeile zu emulieren. Wenn ich das Äquivalent in einer Befehlszeile machen würde, könnte ich ohne zusätzliche Behandlung davonkommen.

+0

Mögliche Duplikat [Wie ein Python subprocess mit Shell = True gestartet beenden] (http://stackoverflow.com/questions/4789837/how-to-terminate-a -python-subprocess-lanced-with-shell-true) –

Antwort

0

Als suggeste d von Jacob, ein Weg (dank eines Kollegen) ist es, mit SIGNAL umzugehen und es an das Kind weiterzugeben. So ein Wrapper wie dies wäre:

import signal 
import subprocess 

def run_cmd(cmd, **kwargs): 
    try: 
     p = None 

     # Register handler to pass keyboard interrupt to the subprocess 
     def handler(sig, frame): 
      if p: 
       p.send_signal(signal.SIGINT) 
      else: 
       raise KeyboardInterrupt 
     signal.signal(signal.SIGINT, handler) 

     p = subprocess.Popen(cmd, **kwargs) 
     if p.wait(): 
      raise Exception(cmd[0] + " failed") 
    finally: 
     # Reset handler 
     signal.signal(signal.SIGINT, signal.SIG_DFL) 
1

Verwenden Sie signal, um SIGINT abzufangen, und veranlassen Sie den Signalhandler, den Subprozess zu beenden.

Schauen Sie sich diese für weitere Informationen (wenn es für Python 2.x ist):

https://docs.python.org/2/library/signal.html

0

nicht sicher, ob es eine Abhilfe ist, aber es funktioniert gut (zumindest unter Windows, die unterschiedlich CTRL + C behandelt)

import subprocess 
try: 
    subprocess.call(r"C:\msys64\usr\bin\sleep 100".split()) 
except KeyboardInterrupt: 
    print("** BREAK **") 
print("continuing the python program") 

Ausführung:

K:\jff\data\python>dummy_wait.py 
** BREAK ** 
continuing the python program