Kill

有沒有不包括 sudo 程序的 sudo pkill 程序的干淨方法?

  • April 13, 2021

我需要殺死一些以 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

嘗試:

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

這是一個使用僅包含單個字母的字元類的技巧p

正則表達式正在尋找/perf,但sudo pkill命令行有/[p]erf,不匹配。

這種方法已經在命令中使用了幾十年,例如ps aux | awk '/[f]oo/ {print $1}'

請注意,pkill/中的模式pgrep是擴展的正則表達式,如grep -E. 因此,您可以只提供一個更精確地針對所需程序的正則表達式。在您的情況下,可能是這樣的:

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

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

可能值得解釋為什麼所有這些都是必需的:

眾所周知,pkill/pgrep永遠不會匹配自己。然而,他們使用的標準是通過匹配PID,即他們檢查匹配的 PID 之一是否是他們的,並且他們精確地排除了那個。

但是通過-fa 執行(使用完整命令行模式選項)sudo,該pkill命令最終也會匹配sudo自己的程序,因為該程序也帶有一個命令行字元串,該字元串與您使用的*裸模式匹配。*顯然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 是一個包含要匹配*的PID 的文件 /

引用自:https://unix.stackexchange.com/questions/644626