Python:为什么在Ubuntu中subprocess()启动2个进程,而在OpenSUSE中只启动1个?

4 投票
3 回答
2731 浏览
提问于 2025-04-16 02:41

我写了一个小的图形界面程序,用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 个回答

0

subprocess.Popen 会返回一个 Popen 对象,这个对象有一些很有用的方法可以使用。直接用 os.kill 来结束进程可能不是个好主意...

如果你使用 Popen 对象的 p.terminate()p.kill() 方法,情况会一样吗?

1

我没有确切的答案,但可以提供几种调查的方法:

可以用 pstree 来查看进程之间的父子关系。

使用 ps -awux 可以查看所有进程的完整命令行参数。

要注意,使用 shell=True 会启动一个 shell 进程(比如 /bin/bash),然后再启动 mplayer。这可能是另一个调查的方向。两个系统使用的是同一个 shell 吗?

两个系统使用的是同一个版本的 mplayer 吗?还有 python 吗?

7

试试这个:

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 解析。

撰写回答