如何编写(从不)匹配零字节的 pgrep 模式?

如何编写(从不)匹配零字节的 pgrep 模式?

我想终止一个名称较长、以foo.目前我的计划是使用pkill(尽管为了测试,为了对过程友好,我一直在检查我的模式pgrep)。我见过这个问题这表明对于长进程名称,您必须使用-f来获取整个命令行。这对于获取长进程名称的其余部分非常有用;问题是,然后模式与整个命令行匹配,而不仅仅是进程名称,我不想意外杀死恰好foo作为参数的不同程序。

所以我相信我想写一个这样的模式:

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

我所写的\0意思是零字节——-f放置在进程的每个参数之前的分隔符。当然\0不行;该模式实际上匹配任何不是\或 (ASCII)的字符序列0。我也尝试过这个:

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

到这里,我确认我的 shell 为 生成了一个 0 字节echo -n '\0'。不幸的是,由于传递参数的方式,pgrep当它看到实际的 0 字节时会停止扫描模式,因此此命令的行为与 完全相同pgrep -f '^[^'——即,它会抛出有关接收无效模式的错误。

如何编写一个引用其中的零字节(或者,任何不是零字节的字节)的模式?

答案1

pgrep -f匹配传递给进程执行的最后一个命令的参数的 SPC 字符串联(如/proc/pid/cmdlineLinux 上所示)。它永远不会包含 NUL 字符。

所以你需要这样做:

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

/path/with space/foo尽管您会错过使用as执行某些命令的进程,但它会报告使用asargv[0]执行命令的进程。foo barargv[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或 with 来更改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

相关内容