简体   繁体   中英

Python communicate is blocked after process kill

I'm running a Python script that executes a Bash subprocess. If the Bash subprocess times out, then the Python script is expected to print the stdout of the Bash subprocess. The Python script works as expected, however, if the Bash subprocess is executed using the "sudo" keyword, then reading the stddout after the timeout blocks the Python.

The Bash script (named test-bash.sh) looks like that:

#!/bin/sh
while :
do
        echo "Press [CTRL+C] to stop.."
        sleep 1
done

The Python script looks like that:

import subprocess
proc = subprocess.Popen("sudo ./test-bash.sh", shell=True, stdout=subprocess.PIPE)
try:
    outs, errs = proc.communicate(timeout=3)
except subprocess.TimeoutExpired:
    proc.kill()
    print("Succesfully killed")
    outs, errs = proc.communicate()
    print("Stdout: {}".format(outs))

The last print is never called, being blocked on communicate(), unless we remove the "sudo" from:

proc = subprocess.Popen("sudo ./test-bash.sh", shell=True, stdout=subprocess.PIPE)

What is the reason for the blocking of communicate()? How do I unblock it and read stddout() if I must run the Bash subprocess using "sudo"?

The problem can be reproduced even without sudo provided that shell=True . It's just like John Bollinger explained above, so I'll spare us the reciting. Fortunately Popen provides a means to deal with such multi-level subprocesses - it allows to start a new session and therewith to create a process group by which all subprocesses can be killed.

# add start_new_session=True argument
proc = subprocess.Popen(…, stdout=subprocess.PIPE, start_new_session=True)
…
# replace proc.kill() by
    import os
    import signal
    os.killpg(proc.pid, signal.SIGTERM)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM