有没有一种干净的方法来处理“sudo pkill”进程而不包含“sudo”进程?

有没有一种干净的方法来处理“sudo pkill”进程而不包含“sudo”进程?

我需要终止一些以 sudo 身份运行的进程,按全名匹配它们,并计算原始命令调用的数量。

对于每个进程有两个进程:命令本身和命令sudo本身,但我可以解决这个问题:

$ sudo -b perf record sleep 100

$ pgrep -fa '/perf record'
2245700 /usr/lib/linux-tools/.../perf record sleep 100

问题是,当我调用 时sudo pkill,它会找到、杀死并计数自身:

$ sudo pkill -ef '/perf record' | wc -l
2

在这种情况下,有没有一种简单的方法可以让 pkill 不包含自身?

我尝试过使用 pid 文件,这是可以接受的,但是缺少 pgrep/pkill 文档,并且它似乎无法以基本形式工作:

$ pgrep -f '/perf record' | tee /tmp/pids
$ sudo pkill -F /tmp/pids
 killed (pid 2249211)

因为它只会杀死第一个。文档说:

       -F, --pidfile file
              Read PID's from file.  This option is perhaps more useful for pkill than pgrep.

但它的含义含糊不清PID's

答案1

尝试:

sudo pkill -ef '/[p]erf record' | wc -l

这是一个使用仅包含单个字母的字符类的技巧p

正则表达式正在寻找/perf,但sudo pkill命令行有/[p]erf,但不匹配。

这种方法已经在像这样的命令中使用了几十年ps aux | awk '/[f]oo/ {print $1}'

答案2

pkill请注意, /中的模式pgrep是扩展的正则表达式,如 中的模式grep -E。因此,您可以只提供一个更精确地针对所需进程的正则表达式。在你的情况下,可能是这样的:

sudo pkill -ef '^(/[^/]+)+/perf record'

甚至更好@cas 描述的技巧在他的回答中。

可能值得解释一下为什么需要所有这些:

众所周知,pkill/pgrep永远不会匹配自己。然而,他们使用的标准是匹配PID, IE他们检查匹配的 PID 之一是否是他们的他们恰恰排除了这一点。

但是通过 a 运行(使用-f完整命令行模式选项)sudo,该pkill命令最终也会匹配sudo自己的进程,因为该命令也带有与 a 匹配的命令行字符串像你使用的那种模式。显然,sudo自己的进程与该进程的 PID 不同pkill,因此pkill不会将该进程从列表中排除,从而杀死sudo生成(并且仍然保留)该进程的pkill进程。

考虑:

$ sudo -b perf record sleep 1234
$ sudo pgrep -fa '/perf record'
1446 /usr/lib/linux-tools/4.2.0-42-generic/perf record sleep 1234
1466 sudo pgrep -fa /perf record  # <-- if I issued a pkill, this process, the sudo, would have been killed

在上面的代码片段中,请pgrep注意自己的进程确实被排除在列表之外。但该sudo进程还带有一个与裸露的正则表达式匹配的命令行。

通过提供更定制的正则表达式,pkill不再包含该sudo pkill -ef <...>进程,因为进程自己的命令行(携带定制的正则表达式)与正则表达式本身不匹配。


关于选项的最后说明-F

在我写这篇文章的时候,这个选项仍然存在只读取一个 PID从文件中。所以是的,文档以及程序的--help输出都具有误导性。来源中的这条评论说的是丑陋的事实。

/* FreeBSD: arg 是一个包含APID匹配*/

答案3

直接获取 pid,避免搜索它:

pid="$(sudo bash -c 'sleep 100 >/dev/null & echo $!')"
sudo kill "$pid"

即使后台进程不输出任何内容,stdout 的重定向也是必要的,因为否则它将被设置为提供 的结果$(),这将导致$()它在尝试从子进程读取时挂起,直到后台任务关闭其 stdout 。

这里的主要好处pkill是您将始终获得正确的 pid,而不是可能杀死与您的搜索匹配的其他进程。例如,如果您同时运行脚本多次,则可能有多个perf进程匹配[p]erf record,每个进程都是脚本每次调用的子进程。

答案4

在即将推出的 procps 4.0.1 中,-A选项被引入pkillpgrep忽略其祖先

这意味着您只需运行以下命令即可避免终止sudo进程:

sudo pkill -Aef '/perf record'

相关内容