Jojo Zhai
Jojo Zhai

Reputation: 61

How to make the subprocess handle the ctrl-c?

I have a python file parent.py as a wrapper to launch another python program child.py. This is the main part of parent.py:

p = subprocess.run(f"python -u {cmd} 2>&1 | tee -a {file_path}", shell=True)

I want to use ctrl-c to control the child process. So in the child.py, I wrote a try-except to catch KeyBoardInterrupt and handle it:

try:
    while True:
        pass
except KeyboardInterrupt:
    print("lalala~~~~~~~~~~~~~~~~~~~~~")

However, if I run the parent.py and then press ctrl-c, the parent has been terminated and the child.py cannot handle the interrupt (no "lalala" output):

^CTraceback (most recent call last): File "/home/zxl/rcd_python1.py", line 27, in p = subprocess.run(f"python -u {cmd} 2>&1 | tee -a {file_path}", shell=True) File "/home/zxl/programs/anaconda3/envs/pyg2/lib/python3.8/subprocess.py", line 495, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/home/zxl/programs/anaconda3/envs/pyg2/lib/python3.8/subprocess.py", line 1020, in communicate self.wait() File "/home/zxl/programs/anaconda3/envs/pyg2/lib/python3.8/subprocess.py", line 1083, in wait return self._wait(timeout=timeout) File "/home/zxl/programs/anaconda3/envs/pyg2/lib/python3.8/subprocess.py", line 1808, in _wait (pid, sts) = self._try_wait(0) File "/home/zxl/programs/anaconda3/envs/pyg2/lib/python3.8/subprocess.py", line 1766, in _try_wait (pid, sts) = os.waitpid(self.pid, wait_flags) KeyboardInterrupt

How can I send the ctrl-c to the subprocess and make it handle it, instead of terminate everything? Thanks a lot~

Upvotes: 0

Views: 165

Answers (2)

pilcrow
pilcrow

Reputation: 58681

This is working already.

When you press Ctrl-C, the terminal driver sends a SIGINT to every member of the foreground process group. [1] In your case, that means each of four processes receives a SIGINT: main.py, it's child shell (subshell=True), and that shell's children child.py and tee.

Your child.py correctly handles the SIGINT and prints "lalalala~~~~". However, this output is piped to tee, meaning you'd never see it on the console. Additionally, tee is itself killed by a SIGINT, almost certainly before it has a chance to read from its input and write to its output. Your main.py, since it doesn't handle the SIGINT, dies with the stack trace you observe.

  1. POSIX.1-2017 Base Definitions, General Terminal Interface, §11.1.9

Upvotes: 1

Sashi
Sashi

Reputation: 89

I am getting the output you expect. Your code is working for me.

test_subprocess.py

import time

if __name__ == '__main__':
    while True:
        try:
            time.sleep(1)
        except KeyboardInterrupt:
            print("lalala")

test_subprocess_main.py

import subprocess

if __name__ == '__main__':
    print('Start')
    p = subprocess.run("python3 test_subprocess.py", shell=True, check=True)

The output.

Mac-sashi:fun sashi$ python3 test_subprocess_main.py
Start
^Clalala
Traceback (most recent call last): File "/Users/sashi/repos/fun/test_subprocess_main.py", line 6, in p = subprocess.run("python3 test_subprocess.py", shell=True, check=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sashi/.pyenv/versions/3.11.1/lib/python3.11/subprocess.py", line 550, in run stdout, stderr = process.communicate(input, timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/sashi/.pyenv/versions/3.11.1/lib/python3.11/subprocess.py", line 1199, in communicate self.wait() File "/Users/sashi/.pyenv/versions/3.11.1/lib/python3.11/subprocess.py", line 1262, in wait return self._wait(timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/sashi/.pyenv/versions/3.11.1/lib/python3.11/subprocess.py", line 1997, in _wait (pid, sts) = self._try_wait(0) ^^^^^^^^^^^^^^^^^ File "/Users/sashi/.pyenv/versions/3.11.1/lib/python3.11/subprocess.py", line 1955, in _try_wait (pid, sts) = os.waitpid(self.pid, wait_flags) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ KeyboardInterrupt

Can you try the code I posted? Does it work for you?

Upvotes: 0

Related Questions