Python:为什么在Ubuntu中subprocess()启动2个进程,而在OpenSUSE中只启动1个?
我写了一个小的图形界面程序,用Python制作的,用户可以用它来听网络电台。这个程序使用Python的subprocess()来启动mplayer,以便调到某个电台,比如:
runn = "mplayer http://77.111.88.131:8010"
p = subprocess.Popen(runn, shell=True)
pid = int(p.pid)
wait = os.waitpid(p.pid, 1)
然后它会保存p.pid,当用户想停止收听时,就会用到以下代码:
os.kill(p.pid, 9)
在OpenSUSE上这个功能运行得很好,但在Ubuntu上就不行了。看起来Ubuntu实际上启动了两个独立的进程。终端输出如下:
OpenSUSE 11.3:
$ pgrep mplayer
22845
Ubuntu 10.04:
$ pgrep mplayer
22846
22847
这个问题在运行其他程序时也会出现。有没有人知道这是为什么?我真的希望这个应用能在所有的Linux发行版上运行,所以任何帮助都非常感谢。
3 个回答
subprocess.Popen 会返回一个 Popen 对象,这个对象有一些很有用的方法可以使用。直接用 os.kill 来结束进程可能不是个好主意...
如果你使用 Popen 对象的 p.terminate() 或 p.kill() 方法,情况会一样吗?
我没有确切的答案,但可以提供几种调查的方法:
可以用 pstree
来查看进程之间的父子关系。
使用 ps -awux
可以查看所有进程的完整命令行参数。
要注意,使用 shell=True
会启动一个 shell 进程(比如 /bin/bash
),然后再启动 mplayer
。这可能是另一个调查的方向。两个系统使用的是同一个 shell 吗?
两个系统使用的是同一个版本的 mplayer 吗?还有 python 吗?
试试这个:
p = subprocess.Popen(runn.split(), shell=False)
我猜测发生了什么事情...
当你使用 shell=True
时,实际上是让程序启动了这个命令 sh -c "你的字符串"
。这里的 sh
命令会解析你的字符串,并执行这个命令,就像你在命令行里直接输入的一样。通常,这会产生两个进程:一个是 sh -c "你的字符串"
,另一个是它的子进程 你的字符串
。
有些版本的 sh
有一种优化功能,在特定条件下会自动执行命令。比如当这是 sh
要执行的最后一个命令,并且 sh
没有其他事情需要做时,它就会这样做。当使用 sh -c
来运行命令时,这几乎总是会导致 sh
自己被它正在运行的命令替代,从而只留下一个进程。
在我看来,使用 subprocess.Popen
时加上 shell=True
是个非常糟糕的主意。这样做会让你面临很多安全问题,而且通常会导致行为不太可预测,因为命令行中的特殊字符会被 sh -c
解析。