Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making sure a Python script with subprocesses dies on SIGINT

Tags:

python

signals

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.

like image 818
ajwood Avatar asked Nov 27 '12 21:11

ajwood


People also ask

How do you end a subprocess call in Python?

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.

What are Subprocesses in Python?

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.

What is Shell true in subprocess 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.

What is sigint Python?

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!


1 Answers

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.

like image 153
udoprog Avatar answered Sep 19 '22 03:09

udoprog