Null

如何編寫一個(從不)匹配零字節的 pgrep 模式?

  • November 21, 2020

我想終止一個以 . 結尾的長名稱的程序foo。目前我的計劃是使用pkill(儘管為了測試,為了對過程友好,我一直在檢查我的模式pgrep)。我已經看到這個問題表明對於長程序名稱,您必須使用-f來獲取整個命令行。這對於獲取長程序名稱的其餘部分非常有用;問題是該模式與整個命令行匹配,而不僅僅是程序名稱,我不想意外殺死碰巧foo作為參數的不同程序。

所以我相信我想寫一個這樣的模式:

pgrep -f '^[^\0]*foo'

我所寫的意思是零字節——在程序的每個參數之前放置\0的分隔符。-f當然\0行不通;此模式實際上匹配任何不是\或 (ASCII)的字元序列0。我也試過這個:

pgrep -f '^[^'`echo -n '\0'`']*foo'

在這裡,我已經確認我的 shell 為echo -n '\0'. 不幸的是,由於參數的傳遞方式,pgrep當它看到實際的 0 字節時停止掃描模式,因此該命令的行為與將完全相同pgrep -f '^[^'- 也就是說,它會引發有關接收無效模式的錯誤。

如何編寫一個引用其中零字節的模式(或者,好吧,任何不是零字節的字節)?

pgrep -f與傳遞給程序執行的最後一個命令的參數的 SPC 字元的串聯匹配(如在/proc/pid/cmdlineLinux 上所見)。那從不包含 NUL 字元。

所以你需要這樣做:

pgrep -f '^[^ ]*foo( |$)'

儘管您會錯過使用/path/with space/fooas執行某些命令的程序,argv[0]但它會報告使用 as 執行命令的foo bar程序argv[0]

在任何情況下,您都不能將參數中的 NUL 傳遞給執行的命令,因為命令參數是 NUL 分隔的字元串。

zsh中,您可以將 NUL 傳遞給內置命令和函式(因為它們不受該限制的影響,execve()因為它們未執行)。所以在 Linux 上,你可以這樣做:

print -rC1 /proc/<->(Ne[$'[[ "${$(<$REPLY/cmdline)%%\0*}" = *foo ]]']:t)

找到argv[0]結束於的程序foo

或者:

print -rC1 /proc/<->/exe(N-.e['[[ $REPLY:A = *foo ]]']:h:t)

對於那些正在執行路徑以結尾的命令的人foo(儘管您可能僅限於自己的程序)。

在 Linux 上,程序名稱限制為 15 個字節,並且在每次呼叫時更改為第一個參數的基本名稱的前 15 個字節execve(),但也可以通過寫入/proc/pid/comm或使用來更改prctl(PR_SET_NAME)。程序也可以改變/proc/pid/cmdline. 參見例如:

$ perl -lne 'BEGIN{$0 = "foo bar 90123456789"}; print "$ARGV: $_"' /proc/self/{cmdline,comm}
/proc/self/cmdline: foo bar 90123456789
/proc/self/comm: foo bar 9012345

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