【发布时间】:2018-01-27 13:10:00
【问题描述】:
当通过 subprocess.Popen() 调用 linux 猫时,我遇到了意想不到的行为。
Python 脚本的结构如下:
import os, subprocess
def _degrade_child_rights(user_uid, user_gid):
def result():
os.setgid(user_gid)
os.setegid(user_gid)
os.setuid(user_uid)
os.seteuid(user_uid)
return result
child = subprocess.Popen("cat /home/myuser/myfolder/screenlog.0",
preexec_fn=_degrade_child_rights(0, 0), shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
当我用 ps aux | 检查执行的 shell 命令时grep cat 它显示 python 成功运行了 shell 命令。
> ps aux | grep cat
root 21236 0.0 0.0 6564 780 pts/1 S 20:49 0:00 /bin/sh -c cat /home/myuser/myfolder/screenlog.0
root 21237 0.0 0.0 11056 732 pts/1 S 20:49 0:00 cat /home/myuser/myfolder/screenlog.0
root 21476 0.0 0.0 15800 936 pts/1 S+ 20:52 0:00 grep --color=auto cat
但是,cat 命令永远不会结束。
我还将 cat $file 命令外包给了一个 bash 脚本。然后 bash 执行我的 cat-call,但也会阻塞。
当我手动执行 cat $file 时,它会按预期运行,因此文件末尾不存在的 EOF 也是不可能的。
我认为,Popen 添加的“/bin/sh -c”会以某种方式与 cat $file 的正确执行混淆。
我能以某种方式阻止这种情况吗?
【问题讨论】:
-
您似乎没有从 cat 标准输出连接到的子进程管道中读取。这意味着一旦管道的缓冲区已满,它将阻塞。您需要从管道中读取数据,或者将子进程的标准输出连接到 Python 进程的标准输出。
-
不,
sh -c与问题无关。传递shell=True告诉Python 你想实际运行sh -c "cat /home/myuser/myfolder/screenlog.0"——如果你不想想要那样,你会想要关闭shell=True参数,并修改其余的命令来表示一个有效的 argv 列表。引号在ps的输出中不可见,因为ps没有以确保其输出可作为命令输入重复使用的方式指定;它在视觉上无法区分句法空间和文字空间。 -
(所以,你不能在
ps输出中区分./myprog "hello world"和./myprog hello world;如果你想要 actual argv,最好的做法是将其从 procfs 中拉出,它以 NUL 分隔的形式提供)。 -
@Magnus Reftel 你是对的,这就是问题所在。奥斯汀耶茨你的答案是正确的,但不适合我的需要。我的方法是在 Popen() 调用之后立即开始的线程中通过 readline() 从管道中读取。启动的线程然后将 readline 的输出放到一个队列中,该队列支持超时。
标签: python linux bash python-2.7 shell