You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python杀死sudo启动的subprocess子进程?

这个问题我之前也碰到过,核心原因是:当你用subprocess启动sudo sleep 100时,sudo进程在完成权限验证后,可能会fork出一个root权限的sleep子进程,随后sudo自身就退出了——这就导致你拿到的PID是已经死掉的sudo进程ID,而真正在跑的sleep是另一个root权限的进程,普通用户根本没法直接杀它。

下面给你几个靠谱的解决方案,按推荐程度排序:

方案1:让sudo直接替换自身为目标进程(拿到真实PID)

绝大多数现代版本的sudo,在无需交互(比如你已经配置了免密sudo)的情况下,会直接用目标进程替换自己(也就是*exec系统调用*),不会fork子进程。这时候subprocess.Popen返回的PID就是sleep的真实PID。如果你的环境里sudo默认不这么做,可以加-n(非交互模式,适合免密场景)和-E(保留环境变量)选项强制一下:

import subprocess
import time

# 启动sudo sleep,拿到真实的sleep PID
pr = subprocess.Popen(["sudo", "-n", "-E", "sleep", "100"])
time.sleep(5)
# 必须用sudo kill,因为sleep是root权限的进程
subprocess.run(["sudo", "kill", str(pr.pid)])

方案2:通过临时文件记录目标进程PID

如果你的sudo确实会fork子进程(比如某些旧版本或特殊配置),可以让sudo启动一个shell,先把目标进程的PID写入临时文件,之后读取这个PID再杀死:

import subprocess
import time
import os

# 用/tmp下的临时文件存PID,避免权限问题
pid_file = "/tmp/sleep_pid.tmp"
# 让sudo启动shell,记录自身PID(shell会exec sleep,所以这个PID就是sleep的PID)
pr = subprocess.Popen(["sudo", "sh", "-c", f"echo $$ > {pid_file}; sleep 100"])
time.sleep(5)
# 读取PID
with open(pid_file, "r") as f:
    sleep_pid = f.read().strip()
# 杀死root进程
subprocess.run(["sudo", "kill", sleep_pid])
# 清理临时文件
os.remove(pid_file)

方案3:杀死整个进程组

当sudo启动sleep时,两者会属于同一个进程组(进程组ID等于sudo的PID)。哪怕sudo退出了,sleep依然会留在这个进程组里。你只需要用sudo来杀死整个进程组就行——之前你失败的原因就是没加sudo:

import subprocess
import time

pr = subprocess.Popen(["sudo", "sleep", "100"])
sudo_pid = pr.pid  # 这个就是进程组ID
time.sleep(5)
# 用sudo杀死进程组,-- -$PGID 表示杀掉PGID为$PGID的所有进程
subprocess.run(["sudo", "kill", "--", f"-{sudo_pid}"])

再复盘下你之前的操作为什么失败:

  • 直接pr.kill():普通用户没有权限给root进程发信号,必然报错权限不足。
  • sudo kill $PID:这里的$PID是已经退出的sudo进程ID,当然杀不到正在跑的sleep。
  • sudo kill -- -$PID:如果是在sudo退出后执行,进程组ID还是原来的sudoPID,但必须用sudo来执行这个命令——普通用户碰不到root进程的进程组。

内容的提问来源于stack exchange,提问作者John Allard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:42:59