I've got a command that I'm wrapping in script
and spawning from a Python script using subprocess.Popen
. I'm trying to make sure it dies if the user issues a SIGINT
.
I could figure out if the process was interrupted in a least two ways:
A. Die if the wrapped command has a non-zero exit status (doesn't work, because script
seems to always return 0)
B. Do something special with SIGINT
in the parent Python script rather than simply interrupting the subprocess. I've tried the following:
import sys import signal import subprocess def interrupt_handler(signum, frame): print "While there is a 'script' subprocess alive, this handler won't executes" sys.exit(1) signal.signal(signal.SIGINT, interrupt_handler) for n in range( 10 ): print "Going to sleep for 2 second...Ctrl-C to exit the sleep cycles" # exit 1 if we make it to the end of our sleep cmd = [ 'script', '-q', '-c', "sleep 2 && (exit 1)", '/dev/null'] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) while True: if p.poll() != None : break else : pass # Exiting on non-zero exit status would suffice print "Exit status (script always exits zero, despite what happened to the wrapped command):", p.returncode
I'd like hitting Ctrl-C to exit the python script. What's happening instead is the subprocess dies and the script continues.
Popen(args) with args as a sequence of program arguments or a single string to execute a child program in a new process with the supplied arguments. To terminate the subprocess, call subprocess. Popen. terminate() with subprocess.
Subprocess in Python is a module used to run new codes and applications by creating new processes. It lets you start new applications right from the Python program you are currently writing. So, if you want to run external programs from a git repository or codes from C or C++ programs, you can use subprocess in Python.
After reading the docs, I came to know that shell=True means executing the code through the shell. So that means in absence, the process is directly started.
A Signal Handler is a user defined function, where Python signals can be handled. If we take the signal SIGINT (Interrupt Signal), the default behavior would be to stop the current running program. We can, however, assign a signal handler to detect this signal and do our custom processing instead!
The subprocess is by default part of the same process group, and only one can control and receive signals from the terminal, so there are a couple of different solutions.
Setting stdin as a PIPE (in contrast to inheriting from the parent process), this will prevent the child process from receiving signals associated to it.
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
Detaching from the parent process group, the child will no longer receive signals
def preexec_function(): os.setpgrp() subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=preexec_function)
Explicitly ignoring signals in the child process
def preexec_function(): signal.signal(signal.SIGINT, signal.SIG_IGN) subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=preexec_function)
This might however be overwritten by the child process.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With