Reputation: 2231
I wish to launch a rather long-running subprocess in Python, and would like to be able to terminate it with ^C
. However, pressing ^C
leads to the parent receiving KeyboardInterrupt
and terminating (and sometimes leaves sleep
as a defunct process).
import subprocess
subprocess.call("sleep 100".split())
How do I have it such that pressing ^C
only terminates the sleep
process (as we'd have on a shell command line), and allow the parent to continue? I believe I tried some combinations of using preexec_fn
, start_new_session
and shell
flags to call
, but with no success.
Edit: I know I can wrap the subprocess
invocation in a try-catch
block, and ignore the keyboard interrupt; but I don't want to do that. My question is this: the keyboard interrupt should have killed the sleep
, and should have been the end of it. Why is then propagated, as it were, to the parent. Or is it like the sleep
process was never the one to receive the interrupt? If not, how would I make it the foreground process?
Again, I'm trying to emulate the parent-child relationship of a command line. If I were to do the equivalent on a command line, I can get away without needing extra handling.
Upvotes: 0
Views: 1920
Reputation: 2231
As suggested by Jacob, one way (thanks to a colleague) to do is to handle SIGNAL and pass it on to the child. So a wrapper like this would be:
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)
Upvotes: 0
Reputation: 140297
Not sure if it's a workaround but it works fine (at least on Windows which handles CTRL+C differently)
import subprocess
try:
subprocess.call(r"C:\msys64\usr\bin\sleep 100".split())
except KeyboardInterrupt:
print("** BREAK **")
print("continuing the python program")
execution:
K:\jff\data\python>dummy_wait.py
** BREAK **
continuing the python program
Upvotes: 0
Reputation:
Use signal
to catch SIGINT, and make the signal handler terminate the subprocess.
Look at this for more information (if it's for Python 2.x):
https://docs.python.org/2/library/signal.html
Upvotes: 1