【发布时间】:2021-04-01 16:05:48
【问题描述】:
我正在运行一个执行 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))
最后一个 print 永远不会被调用,在通信()上被阻止,除非我们从以下位置删除“sudo”:
proc = subprocess.Popen("sudo ./test-bash.sh", shell=True, stdout=subprocess.PIPE)
communicate() 阻塞的原因是什么?如果我必须使用“sudo”运行 Bash 子进程,如何解除阻塞并读取 stddout()?
【问题讨论】:
-
我的猜测是,当超时发生时,Python 只会杀死它开始运行
sudo命令的shell,而不是sudo命令本身或它的shell,反过来,开始运行你的 shell 脚本。communicate()然后没有被阻塞,本身,它只是在子进程的标准输出中看不到文件结尾,因为另一端的 shell 仍在运行并保持写入端打开。 -
你可以试试
subprocess.Popen(..., shell=False, ...)。我不确定你认为在 Python 和你首先运行的命令之间插入一个 shell 会得到什么。然而,这可能仍然无法解决问题,因为它只会剥掉三层洋葱的外层。 -
谢谢。关于杀死外壳的猜测是正确的,但在我的具体情况下,我无法摆脱 shell=True。 Armali 提供的建议 kill the entire process group 的解决方案帮助解决了这个问题,无论 shell 参数设置为 True 还是 False。
标签: python linux bash subprocess