如何使用 Python 中的 subprocess 模块启动和停止 Linux 程序?
Posted
技术标签:
【中文标题】如何使用 Python 中的 subprocess 模块启动和停止 Linux 程序?【英文标题】:How do I start and stop a Linux program using the subprocess module in Python? 【发布时间】:2011-07-27 20:30:14 【问题描述】:我正在编写一个使用 Selenium 对另一个网站进行屏幕抓取的网络应用程序。这种屏幕抓取每天只发生一次,所以我宁愿不要让 Selenium 和 Xvfb 一直运行。
我试图弄清楚如何从 Python 启动 Xvfb 和 Selenium,然后在屏幕抓取完成后停止它们。
如果我手动操作,我会在命令行启动它们,然后按 CTRL C 来停止它们。我正在尝试用 Python 做同样的事情。
我好像可以这样成功启动Xvfb:
xvfb = Popen('Xvfb :99 -nolisten tcp', shell=True)
但是当我试图终止它时:
xvfb.terminate()
然后尝试再次启动它(通过重复我的初始命令),它告诉我它已经在运行。
【问题讨论】:
这获得了 5 票赞成?我以为我真的很愚蠢! 在xvfb.terminate()
之后尝试xvfb.wait()
。如果做不到这一点,请尝试xvfb.kill()
。
Ctrl-C 将 SIGTERM 发送到 Unix 进程。您的用户 python 进程无法将 SIGTERM 发送到以 root 身份运行的 Xvfb。获取您孩子的 pid,执行“sudo kill 我不知道您为什么要以 root 身份运行 Xvfb。您通常的 X 服务器只需要以 root 身份运行(在许多但不是所有的 unice 上),以便它可以访问视频硬件;根据定义,这对 Xvfb 来说不是问题。
tempdir = tempfile.mkdtemp()
xvfb = subprocess.Popen(['Xvfb', ':99', '-nolisten', 'tcp', '-fbdir', tempdir])
当您终止 X 服务器时,您可能会看到 zombie process。这实际上不是一个进程(它已经死了),只是进程表中的一个条目,当父进程读取子进程的退出状态或自身死亡时消失。僵尸大多是无害的,但调用wait
读取退出状态会更干净。
xvfb.terminate()
# At this point, `ps -C Xvfb` may still show a running process
# (because signal delivery is asynchronous) or a zombie.
xvfb.wait()
# Now the child is dead and reaped (assuming it didn't catch SIGTERM).
【讨论】:
@Gilles:啊,明白了——我已经复制并粘贴了我用来从某处网页启动 Xvfb 的命令。我没有意识到这是fbdir
选项,如果我不以 root 身份运行它,它会导致它无法工作。我现在已经删除了它,并且可以像我的普通用户一样运行它,但是 .terminate()
和 .kill()
似乎仍然没有停止 Xvfb。
@Paul:我在Popen
通话中犯了几个错别字,但我认为你没看错。你确定.terminate()
和.kill()
没有终止进程吗?僵尸可能仍然存在(当您的 Python 脚本终止时它会消失),请参阅我的编辑。
@Gilles:是的,看起来这个过程正在徘徊。在.terminate()
、.kill()
和我退出 Python shell 之后,ps -C Xvfb
仍然报告 Xvfb 正在运行。当我尝试再次启动 Xvfb 时,它还说服务器已经处于活动状态。 (我认为这只是因为文件/tmp/.X99-lock
仍然存在,但ps -C Xvfb
确认该进程仍在运行。)
@Gilles: AHA — 但是当我按照您建议的方式使用Popen
(即使用参数,而不是字符串和shell=True
)时,一切正常如你所说。呸!非常感谢您对此进行调查,我缺少一些基本的 Unix/Linux 知识,因此在尝试调试问题时往往会有点难过。愿你的答案获得一千个赞。
@Paul:啊,所以你是在杀死 shell 而不是 Xvfb。如果您需要在调用 Xvfb 之前而不是之后进行 shell 扩展,您可以运行 Popen("exec Xvfb …", shell=True)
以便 Xvfb 进程将替换 shell 而不是作为子进程运行。如果你之后需要 shell,你需要以某种方式将 Xvfb 的进程 ID 传递给 python 代码。但是在这里,不使用 shell 是最简单的。【参考方案2】:
我假设您可以对系统进行参数化,以允许任何用户启动 Xvfb,正如 here 解释的那样,解决您的所有问题
编辑 正确的命令行是
sudo chmod u+s `which Xvfb`
【讨论】:
可能——其中哪一部分允许任何用户启动 Xvfb?是sudo mod u+s
which Xvfb``?我不熟悉mod
命令,而且它对谷歌搜索有点免疫——你能扩展一下吗?
事实上它应该是chmod u+s
,正如这里所解释的en.wikipedia.org/wiki/Chmod
我怀疑mod
命令的存在是为了对命令有帮助,只需写man command
@Xavier:啊!事实上,这非常适合让非 root 用户运行 Xvfb。不幸的是,.terminate()
和 .kill()
似乎仍然没有停止这个过程。
@Paul 你是对的我错过了事实上它会启动一个根程序并识别为根。但是您的程序仍然以 root 身份运行以上是关于如何使用 Python 中的 subprocess 模块启动和停止 Linux 程序?的主要内容,如果未能解决你的问题,请参考以下文章
为啥不在 Python 中的 subprocess.Popen 中使用 `shell=True`? [复制]
如何使用 python 2.7.6 使 subprocess.call 超时?
如何在 python 中杀死使用 subprocess.call 调用的子进程? [复制]