Python 进程终止后通信被阻止
Python communicate is blocked after process kill
我正在 运行ning 一个执行 Bash 子进程的 Python 脚本。如果 Bash 子进程超时,那么 Python 脚本应该打印 Bash 子进程的标准输出。 Python 脚本按预期工作,但是,如果使用“sudo”关键字执行 Bash 子进程,则在超时后读取 stddout 会阻塞 Python.
Bash 脚本(名为 test-bash.sh)看起来像这样:
#!/bin/sh
while :
do
echo "Press [CTRL+C] to stop.."
sleep 1
done
Python 脚本如下所示:
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))
最后一次打印永远不会被调用,在 communicate() 上被阻止,除非我们从以下位置删除“sudo”:
proc = subprocess.Popen("sudo ./test-bash.sh", shell=True, stdout=subprocess.PIPE)
communicate()阻塞的原因是什么?如果我必须使用“sudo”运行 Bash 子进程,我该如何解锁它并读取 stddout()?
如果 shell=True
,即使没有 sudo
也可以重现问题。就像 John Bollinger 上面解释的那样,所以我就不复述了。幸运的是 Popen
提供了一种处理此类多级子进程的方法 - 它允许启动一个新会话并由此创建一个进程组,通过该进程组可以终止所有子进程。
# 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)
我正在 运行ning 一个执行 Bash 子进程的 Python 脚本。如果 Bash 子进程超时,那么 Python 脚本应该打印 Bash 子进程的标准输出。 Python 脚本按预期工作,但是,如果使用“sudo”关键字执行 Bash 子进程,则在超时后读取 stddout 会阻塞 Python.
Bash 脚本(名为 test-bash.sh)看起来像这样:
#!/bin/sh
while :
do
echo "Press [CTRL+C] to stop.."
sleep 1
done
Python 脚本如下所示:
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))
最后一次打印永远不会被调用,在 communicate() 上被阻止,除非我们从以下位置删除“sudo”:
proc = subprocess.Popen("sudo ./test-bash.sh", shell=True, stdout=subprocess.PIPE)
communicate()阻塞的原因是什么?如果我必须使用“sudo”运行 Bash 子进程,我该如何解锁它并读取 stddout()?
如果 shell=True
,即使没有 sudo
也可以重现问题。就像 John Bollinger 上面解释的那样,所以我就不复述了。幸运的是 Popen
提供了一种处理此类多级子进程的方法 - 它允许启动一个新会话并由此创建一个进程组,通过该进程组可以终止所有子进程。
# 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)