在 python 中杀死 sudo 启动的子进程

Killing sudo-started subprocess in python

我是 运行 用户,无需提供密码即可进行根级调用。我的用户目前正在做这样的事情

pr = subprocess.Popen("sudo sleep 100".split())
sleep(5)
pr.kill()

但这会导致此错误,因为用户不是 root,因此它无法终止 root 进程

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 1572, in kill
    self.send_signal(signal.SIGKILL)
  File "/usr/lib/python2.7/subprocess.py", line 1562, in send_signal
    os.kill(self.pid, sig)
OSError: [Errno 1] Operation not permitted

所以我尝试做这样的事情

pr = subprocess.Popen("sudo sleep 100".split())
sleep(5)
kill_pr = subprocess.Popen("sudo kill {}".format(pr.pid))

但这不会终止相关进程。例如,如果

>> subprocess.Popen("sudo sleep 100".split()).pid
5000

但是

$ pgrep sleep
5001

所以似乎从 subprocess.Popen("..").pid 返回的 pid 比进程的实际 pid 高一个 运行 我要终止的命令

我假设从 Popen 调用返回的 pid 是父进程,所以我尝试做类似

sudo kill -- -$PID,其中 $PID 是从 Popen 返回的那个,但这只给了我

kill: sending signal to -2100 failed: No such process

为什么进程不存在?

本质上,我只需要一种方法来 运行 使用 sudo 的命令,使用 python 的子进程,然后在需要时能够终止它。我假设我需要 运行 某种类型的 sudo kill 命令和我试图杀死的进程的 pid 或类似的东西,但我无法确定具体如何做到这一点。

当您执行 pgrep sleep 时,您会看到 sleep 命令的 PID,运行 作为您创建的 sudo 进程的子进程。

作为快速演示,我将以下内容保存为 subproc.py

import subprocess
pr = subprocess.Popen(["sudo", "sleep", "100"])
print("Process spawned with PID: %s" % pr.pid)

当运行这个脚本时,我们可以看到产生了两个进程:

~/$ python subproc.py
Process spawned with PID: 5296

~/$ ps all | grep sleep
    0  5296     1     sudo sleep 100
    0  5297  5296     sleep 100

您会注意到您在代码中知道的 PID 是 'parent' sudo 进程。这是您应该终止的进程,但您需要使用 sudo 来执行此操作:

subprocess.check_call(["sudo", "kill", str(pr.pid)])
#You might want to wait for the process to end:
os.waitpid(pr.pid, 0)

我想我明白了,问题是如果我这样做

import subprocess, os
pr = subprocess.Popen(["sudo", "sleep", "100"])
print("Process spawned with PID: %s" % pr.pid)
pgid = os.getpgid(pr.pid)
subprocess.check_output("sudo kill {}".format(pgid))

它会终止启动 python 解释器的进程

>>> Terminated

所以我将 preexec_fn 设置为 os.setpgrp

import subprocess, os
pr = subprocess.Popen(["sudo", "sleep", "100"], preexec_fn=os.setpgrp)
print("Process spawned with PID: %s" % pr.pid)
pgid = os.getpgid(pr.pid)
subprocess.check_output("sudo kill {}".format(pgid))

在另一个shell中,如果我检查

pgrep sleep

什么都没有出现,所以它实际上被杀死了。

我对 root 子进程有同样的问题,但这里和这里的答案 - Python how to kill root subprocess 对我不起作用。

最后唯一起作用的是:

proc = subprocess.Popen(["sudo", exe_path], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
.
.
.
os.system("sudo pkill -9 -P " + str(proc.pid))

无需- preexec_fn=os.setpgrp