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

Mar*_*cus 6 kill pkill

我需要杀死一些作为 sudo 运行的进程,按全名匹配它们,并计算原始命令调用的次数。

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

$ sudo -b perf record sleep 100

$ pgrep -fa '/perf record'
2245700 /usr/lib/linux-tools/.../perf record sleep 100
Run Code Online (Sandbox Code Playgroud)

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

$ sudo pkill -ef '/perf record' | wc -l
2
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

       -F, --pidfile file
              Read PID's from file.  This option is perhaps more useful for pkill than pgrep.
Run Code Online (Sandbox Code Playgroud)

但它的含义是模棱两可的PID's

cas*_*cas 13

尝试:

sudo pkill -ef '/[p]erf record' | wc -l
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 难道`pkill` 和`pgrep` 不是为了让我们不必使用这样的技巧而创建的吗?我以为他们总是避免匹配自己。 (4认同)
  • @Barmar 他们确实避免匹配自己。只是通过运行 `sudo` 它们匹配了 `sudo` 自己的进程,而不是 `pgrep`/`pkill` 进程。`sudo` 进程命令行也携带一个字符串,该字符串匹配 _bare_ 模式,就像 OP 的模式一样。 (4认同)

LL3*_*LL3 6

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

sudo pkill -ef '^(/[^/]+)+/perf record'
Run Code Online (Sandbox Code Playgroud)

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

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

众所周知,pkill/pgrep从不匹配自己。然而,他们使用的标准是通过匹配PID,即他们检查匹配的 PID之一是否是他们的,并且他们精确地排除了那个。

但是通过 a 运行(使用-f完整命令行模式选项)sudo,该pkill命令最终sudo也会匹配自己的进程,因为那个进程也带有一个命令行字符串,该字符串与您使用的那种模式匹配。显然sudo自己的进程与那个进程不同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
Run Code Online (Sandbox Code Playgroud)

在上面的代码片段音符是怎么pgrep自己的过程列表确实排除。但是该sudo过程还带有一个与裸正则表达式匹配的命令行。

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


关于-F选项的最后说明。

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

/* FreeBSD: arg 是一个包含要匹配PID的文件*/