如何解析/proc/pid/cmdline

23

我试图在 Linux 上分离进程的 cmdline,但似乎无法依赖它以 '\0' 字符分隔。您知道为什么有时会使用 '\0' 字符作为分隔符,而有时则是普通空格吗?

您知道检索可执行文件名称和路径的其他方法吗?我一直在尝试用 'ps' 获取此信息,但它总是返回完整的命令行,可执行文件名称被截断。

谢谢。

8个回答

24

使用 strings

$ cat /proc/self/cmdline | strings -1
cat
/proc/self/cmdline

1
对于busybox用户:cat /proc/self/cmdline | strings -n 1 - dubbaluga
这也是我的首选方式,但是大多数发行版默认都带有strings命令,而几乎没有Docker基础镜像带有该命令。所以,结果可能因人而异 - undefined

20

/proc/PID/cmdline 始终由 NUL 字符分隔。

要了解空格,请执行此命令:

cat -v /proc/self/cmdline "a b" "c d e"

编辑:如果你真的看到了不该有的空格,或许你的可执行文件(有意或无意地)写入了 argv[],或者正在使用 setproctitle()

当进程由内核启动时,cmdline 是以 NUL 分隔的,而内核代码只是简单地复制在进程启动时 argv[] 存储的内存范围到输出缓冲区,当你读取 /proc/PID/cmdline 时。


就像我之前所说的,当我向一位同事解释“解决方案”时,我意识到他的命令行并没有像我预期的那样表现。我们都在使用Ubuntu,所以我不知道这是否是可以配置的行为或取决于所使用的内核。 - ryotakatsuki
这是错误的。有时参数之间会有空格 - 即所有内容都在argv [0]中。我知道这一点,因为我已经看到过这种情况。 - camh
程序对参数向量的可变性是我反对你的说法的原因。如果你没有说“总是”并强调它,我就不会评论了。 - camh
嗯,有趣。我得检查一下,但我认为这发生在所有进程中。我不记得我检查过哪个进程了。感谢更新 :) - ryotakatsuki
我一直认为它们都是NUL分隔的,直到我发现一个不是的过程。那就是postgrey——一个使用Net::Server的Perl程序,可以在一个参数中重写命令行。 - camh
实际上,我认为说在参数(如argv[]的成员)之间有空格是不正确的,但是,在一个参数内部可能会有空格,这些空格可能分隔了某些子部分,而某些人(错误地?)希望将它们视为不同的参数。 - Chris Stratton

17

使用

tr "\0" " " /proc/2634/cmdline

要以空格分隔参数,就像在命令行上看到的那样。
但要注意,以这种方式打印时,无法区分带有空格的参数("a b")和两个单独的参数("a" "b")。

4
当“tr”足以完成工作时,无需使用“cat+tr”,请参考@hek2mgl的答案。 - Patrick Allaert
如果您希望每个参数在单独的一行上,可以使用管道符号 tr "\0" "\n",这对于复杂命令行的可读性有时非常有用。 - Per Lundberg

15

/proc/PID/cmdline 中的命令行参数是用空字节分隔的。您可以使用 tr 命令将它们替换为新行:

tr '\0' '\n' < /proc/"$PID"/cmdline

3
供应商盒子并不总是有 "strings",它们通常有 "tr"。 - jouell

4
暗中一擊,不過有可能嗎\0是用來分隔詞語的,而空格是在一個詞語中分隔單詞的嗎?例如,
myprog "foo bar" baz

可能会出现在/proc/pid/cmdline中...

/usr/bin/myprog\0foo bar\0baz

我完全是猜测,似乎在我的一台Linux机器上找不到任何空间。


1
你好。正如你所提到的,空格用于分隔同一术语中的单词,这也是我所期望的,但我有一台机器可以使用空格来分隔术语。它是一个Ubuntu系统,不知道具体是哪个版本。 - ryotakatsuki

2

超级简单的方法(但仅适用于一个进程,而不是批量解析等):

$ cat /proc/self/cmdline "a b" "cd e" | xargs -0

工作原理:默认情况下,xargs 只会将其输入进行 echo 操作,而 -0 开关则允许其读取以 null 分隔的行,而非以换行符分隔的行。


2
请看我的答案这里,它涵盖了我在尝试此操作时所发现的内容。
编辑:请查看debian-user线程中的bash脚本,它尽最大努力实现您想要的功能(在该线程中查找脚本的第3版)。

嗨。我已经在跟踪进程的路径方面做了类似的事情,读取exe符号链接,但是最大的问题是获取cmd中的可执行文件名。我的意思是,通常当您引用进程可执行文件时,会说:“我想要emacs的PID”,因此您期望找到“emacs”,而不是exe指向的“/usr/bin/emacs22-gtk”。我没有考虑到readlink报告的“(已删除)”字符串。如果我能正确地拆分cmdline中的信息,我可以将其信息与“exe”提供的信息混合在一起。无论如何,似乎没有明显的方法:)。谢谢! - ryotakatsuki
我添加了一个链接到一个帖子,其中包含我的实现脚本。它不能处理带有空格的可执行文件名,但它们很少见(以至于我从未见过)。 - camh

0

可执行文件名称:

cat /proc/${pid}/comm

可执行文件路径:

readlink -f /proc/${pid}/exe

如果您使用的是最新版本的Bash,您可以使用mapfile将命令行分割成其参数,并将它们放入一个名为“command_line”的数组中,如下所示:
mapfile -d '' -t command_line < "/proc/${pid}/cmdline"

更多关于/proc/的信息请参见: proc(5) — Linux手册页面

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接