我正在尝试调试一个失败的旧进程监视器,该监视器搜索正在运行的进程。我确定这是由一些神秘的 Linux 行为引起的。正在运行的进程是 /opt/my/path/directoryname/daemonname 但由于某些奇怪的原因,它在目录名周围显示空格,而不是 /。许多守护进程都从同一目录运行,并以正确的路径显示。它只是每台服务器上的一个特定守护进程。
ps -ef
显示此守护程序的以下内容:
/opt/my/path directoryname daemonname --arg1 VALUE1 --arg-two VALUE.TWO --arg-three ARG.UMENT.THREE.ERR --worker daemonname --pid-role daemonname
该守护进程由 perl 脚本启动。与其他脚本相比,看起来目录路径是使用与所有其他脚本完全相同的环境变量提供的,但这些其他脚本会产生正确的路径,例如/opt/my/path/directoryname/daemonname
. 相关的 perl 行看起来像这样exec => catfile( $settings->config("/directories/executables"), $daemon_name ),
,我已经确认 config("/directories/executables") 的值是正确的值/opt/my/path/directoryname
由于所有有关目录名称包含空格的问题,搜索这个问题一直是一场噩梦。这不是那个。任何路径都不应包含空格。 ps 显示了我的 mkdir 命令,其中有一个空格,其中有一个斜线,这是我能找到的最接近的,但没有得到答复。
返回的字段之一
ps -f
是传递给进程(或其祖先之一)最后执行的命令执行的参数列表。您可以通过ps -o args
.当进程执行文件时,这是通过
execve()
系统调用:arg0
按照惯例,是可执行文件的名称。当 shell 解释:命令行,它调用
execve("/path/to/cmd", ["cmd", "arg", 0], ...)
. 当那是:它调用
execve("/path/to/cmd", ["/path/to/cmd", "arg", 0], ...)
.这些字符串 (
cmd
,arg
) 最终位于进程堆栈的底部,以 NUL 分隔。在这个过程中,这就是argv[0]
,argv[1]
... 所指的。在 Linux 上,该区域在 中公开
/proc/<pid>/cmdline
,这就是ps
从现场获取它的地方args
。从技术上讲,
ps
获取该字符串列表并打印它并用空格连接,以便最终字段args
看起来像用于执行命令的 shell 命令行。在这里,如果
ps
显示:这些空格可能表示这些字符串中的真实空格,或者单独的字符串,或者这些字符串中的空格已被 NUL 替换。
如果进程碰巧使用标准
strtok()
函数或类似的方法将argv[0]
其拆分为/
s ,可能会找出它所运行的可执行文件的基本名称或其路径的不同目录组件,则后者是合理的。例如,如果我创建:
并编译并运行它:
您会看到
/
s 已被空格替换。实际上,它们已被 NUL 取代,可以通过以下方式验证:
但
ps
看到这些 NUL 并将它们解释为 3 个不同参数的分隔符,并用空格连接起来。然后假设这是正确的解释,这不是一个奇怪的 Linux 行为,它只是应用程序本身
argv[0]
在启动后修改它(可能通过用/
NUL 替换 s,可能是为了提取一些路径组件)。在 Linux 上,查找进程当前正在运行的可执行文件的更可靠方法是执行
readlink()
on/proc/<pid>/exe
,例如使用realpath
orreadlink
实用程序或stat
内置的zsh
:Linux 上的 procps 实现
ps
将其返回为ps -o exe
.没有万无一失的方法可以确定传递给命令的参数是什么,因为
/proc/<pid>/cmdline
进程可以修改显示的内容。不过,审核日志可能包含这些信息。