进程终止后Python通信被阻止
我正在运行一个执行Bash子进程的Python脚本。如果Bash子进程超时,那么Python脚本将打印Bash子进程的stdout。但是,如果使用“sudo”关键字执行Bash子进程,那么在超时后读取stddout会阻塞Python,那么Python脚本将按预期工作 Bash脚本(名为test Bash.sh)如下所示:进程终止后Python通信被阻止,python,linux,bash,subprocess,Python,Linux,Bash,Subprocess,我正在运行一个执行Bash子进程的Python脚本。如果Bash子进程超时,那么Python脚本将打印Bash子进程的stdout。但是,如果使用“sudo”关键字执行Bash子进程,那么在超时后读取stddout会阻塞Python,那么Python脚本将按预期工作 Bash脚本(名为test Bash.sh)如下所示: #!/bin/sh while : do echo "Press [CTRL+C] to stop.." sleep 1 d
#!/bin/sh
while :
do
echo "Press [CTRL+C] to stop.."
sleep 1
done
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))
Python脚本如下所示:
#!/bin/sh
while :
do
echo "Press [CTRL+C] to stop.."
sleep 1
done
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))
除非我们从以下位置删除“sudo”,否则不会调用最后一次打印,在Communication()上被阻止:
阻止Communication()的原因是什么?如果必须使用“sudo”运行Bash子进程,如何取消阻止并读取stddout()。如果
shell=True
,即使没有sudo
,问题也可以重现。这就像约翰·博林格在上面解释的,所以我不会让我们背诵了。幸运的是,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)
我的猜测是,当超时发生时,Python只杀死它启动的shell来运行
sudo
命令,而不是sudo
命令本身或它开始运行shell脚本的shellcommunicate()
则不会被阻止,就其本身而言,它只是在子进程的标准输出上看不到文件的结尾,因为另一端的shell仍在运行并保持写端打开。您可以尝试subprocess.Popen(…,shell=False,…)
。我不确定您认为在Python和您首先运行的命令之间插入shell会带来什么好处。不过,这可能仍然不能解决问题,因为它只会剥下三层洋葱的外层。谢谢。关于杀死外壳的猜测是正确的,但在我的具体案例中,我无法摆脱外壳=真。Armali提供的解决方案提出了杀死整个流程组的方法,帮助解决了这个问题,不管shell参数设置为True还是False。它成功了!谢谢