在ps命令中使用自定义分隔符的技术解析

本文详细讨论了在Debian系统升级后ps命令自定义分隔符功能失效的问题,涉及procps-ng版本变更、AIX自由格式支持的技术细节,并提供了使用旧版本ps和Docker容器的两种解决方案。

Custom separator in ps

问题描述

我在一个过时的Debian 10系统中的bash脚本中使用了以下命令:

1
ps -axo "%p ;;; %a"

这个命令工作正常,输出格式如下:

1
2
3
4
10161 ;;; [kworker/0:1-cgroup_destroy]
12173 ;;; [kworker/2:0-events]
12379 ;;; [kworker/u8:0-events_unbound]
12464 ;;; [kworker/u8:1-flush-254:2]

自定义分隔符;;;在进程ID和进程名称之间,这正是我想要的!

现在我将系统升级到当前的Debian 13,这个功能不再工作了。如果没有自定义分隔符,命令仍然正常工作:

1
ps -axo "%p %a"

输出:

1
2
3
4180 [kworker/0:1-ata_sff]      
4181 [kworker/3:1-ata_sff]      
4292 [kworker/2:2-ata_sff]

但是使用自定义分隔符时:

1
ps -axo "%p ;;; %a"

出现错误:

1
Error: must set personality to get -x option

我不知道从Debian 10到13的升级过程中什么时候这个功能被破坏了。有任何想法如何恢复我的自定义分隔符功能吗?

版本信息:

1
2
ps -V
ps from procps-ng 4.0.4

技术解答

答案1

文档表明这个功能本来不应该工作,这种看法也被广泛认同,所以在版本4.0.3中这个功能的丢失没有引起太多反应(行为变化是由于对%cpu处理的一个晦涩且不完整的修复)。然而,实际上"AIX自由格式"确实应该工作,最近已经恢复了;不幸的是,修复只在procps的4.0.5版本中可用,这个版本在Debian中还没有提供,更不用说在Debian 13中了。

我不知道在您当前情况下使用Debian 13中的ps版本有什么解决方法;您可以构建更新版本的ps,也许可以在Debian中提交一个问题指向上游修复。这不太可能符合稳定版修复的条件;我认为在Debian本身中最好的希望是等待4.0.5进入测试版后进行回溯。

您当然可以在某处保留Debian 10或更好的11版本的ps并使用它;如果您手头没有,可以按以下方式下载并提取(在amd64上):

1
2
3
$ wget http://deb.debian.org/debian/pool/main/p/procps/libprocps8_3.3.17-5_amd64.deb http://deb.debian.org/debian/pool/main/p/procps/procps_3.3.17-5_amd64.deb
$ sudo apt install ./libprocps8_3.3.17-5_amd64.deb
$ dpkg-deb -x procps_3.3.17-5_amd64.deb myps

myps/bin/ps复制到PATH上的其他地方,重命名为myps,然后您就可以运行:

1
$ myps -axo "%p ;;; %a"

并获得您期望的结果。ps中偶尔会发现漏洞,所以依赖一个非常旧的版本进行常规使用可能不是一个好主意。

答案2

一个完整的可用解决方法,使用Docker容器来提供特定版本的procps,这里是4.0.5(来自Stephen Kitt答案的最新工作版本),而不会弄乱apt和您的系统(通过设计隔离):

4.0.5版本的库要求/依赖:

1
2
3
4
5
6
7
8
$ ldd /usr/bin/ps
    linux-vdso.so.1 (0x00007fff88d94000)
    libproc2.so.1 => /lib64/libproc2.so.1 (0x00007f8bfa136000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f8bf9f3c000)
    libsystemd.so.0 => /lib64/libsystemd.so.0 (0x00007f8bf9e28000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f8bfa1b4000)
    libcap.so.2 => /lib64/libcap.so.2 (0x00007f8bf9e1a000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f8bf9d32000)

在终端中复制/粘贴的解决方案:

先决条件(这里以Debian为例)

1
2
# apt install docker.io
# systemctl enable --now docker.service

安装/配置:

1
2
3
4
5
6
cat>Dockerfile<<EOF
FROM opensuse/leap:16.0
RUN zypper -n refresh && zypper -n install procps
ENTRYPOINT ["ps"]
EOF
docker build -t ps:latest .

使用:

1
2
3
4
5
6
docker run \
    --rm \
    --pid=host \
    -v /etc:/host-etc:ro \
    -v /proc:/host-proc:ro \
     ps -axo "%p ;;; %a"

完成了…

如果您需要简化这个长命令,甚至可以创建一个shell别名。

注意: 这不特定于procps,当您需要在受限/私有网络(我指的是不暴露给整个互联网的服务)中使用特定版本的应用程序(甚至是过时的,如PhpLdapAdmin)时,这是您的最佳选择。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计