从 ps 输出中排除 ps 本身

从 ps 输出中排除 ps 本身

我想获取系统中所有进程的信息除了ps过程本身。

也就是说,类似:

ps --no-headers --pid 1111 -N

在哪里1111是进程ID现在运行ps命令。

我尝试过类似的东西

ps --no-headers --ppid $$ -N

然而,这确实不行何时ps在“子进程”中运行,例如:

IFS=' ' read pctd proc <<<$(/bin/ps --no-headers --ppid $$ -No pcpu,pid,comm --sort=+pcpu | tail -n 1)

最后一个命令尝试获取“最近”使用最多 CPU 的进程的 CPU 使用百分比和进程 ID 以及名称。

IFS=' ' read pctd proc <<<$(/bin/ps --no-headers -eo pcpu,pid,comm --sort=+pcpu | tail -1)

直到最近都工作正常。然而,更新到 Ubuntu 23.04(或内核 6.x)后ps开始有时将自己列为使用 100% CPU


目前,以下似乎是一种解决方法(但并不安全):

IFS=' ' read pctd proc <<<$(/bin/ps --no-headers -eo pcpu,pid,comm --sort=+pcpu | grep -v \ ps | tail -1)

答案1

排除ps自身:

sh -c 'exec ps --no-headers --pid "$$" -N'

sh将其自己的 PID 替换为$$,但随后将其自身替换为ps。 PID不改变,这就是exec工作原理。这种方式ps接收它自己的 PID 作为 的选项参数--pid

注意此方法排除 ps本身而不是其他ps进程(如果有)。

答案2

作为一般化如何去除ps自己的条目,特别是对于ps不支持非标准-N/--deselect选项的实现,常见的做法是:

print_pid_and_run() {
  sh -c 'echo "$$" && exec "$@"' sh
}
print_pid_and_run ps ...ps-options... |
  awk 'NR == 1 {pid = $0; next}
       $1 != pid'

(根据传递给的选项,更改输出$1中具有进程 pid 的实际字段)。psps

在 zsh 中,sh可以通过执行以下操作来避免运行:

zmodload zsh/system
print_pid_and_run() (echo $sysparams[pid] && exec "$@")

在bash中:

print_pid_and_run() (echo "$BASHPID" && exec "$@")

(请记住bash,与上面相反zsh, in 不能用于运行内置函数或函数)。

答案3

不是对您问题的回答,而是对您的评论:

IFS=' ' read pctd proc <<<$(/bin/ps --no-headers --ppid $$ -No pcpu,pid,comm --sort=+pcpu | tail -n 1)

最后一个命令尝试获取“最近”使用最多 CPU 的进程的 CPU 使用百分比和进程 ID 以及名称。

我不知道,你的方法在那里被误导了。pcpu返回自进程存在以来任何 CPU 运行进程的任何线程所花费的时间与总时间的比率。

例如,一个进程可能会启动,花几毫秒初始化自身,就像执行命令时一样(在此期间,它可能会在 1 毫秒内使用接近 100% 的 CPU),然后休眠 10 小时,然后生成 20 个线程,充分利用 20 个线程。 CPU 持续 1 分钟(top例如,在此期间将显示 2000% CPU 使用率)。如果此时运行ps -o pcpu,该进程将在总共 601 分钟内使用 20 分钟的 CPU,因此您会看到大约 3%,而不是 2000%。另一方面,如果您碰巧在命令启动ps时运行该命令,可能会发现该进程使用了​​ 1 毫秒的 CPU 时间超过 1 毫秒,并报告 100% CPU 利用率。sleep 1hps

如果您想获取仍在运行且在过去 3 秒内使用最多 CPU 时间的进程,您需要在某一时刻收集所有进程的 CPU 时间,然后在 3 秒后再次收集并执行以下操作:减法,你不能使用ps -o pcpu它,或者你可以top在批处理模式下使用一些类似的应用程序来为你进行计算。

答案4

像这样,使用过滤器丢弃ps

$ read pctd pid proc < <(
    ps --no-headers -eo pcpu,pid,comm |
        awk '$1>=max && $3!="ps"{max=$1; val=$0}END{print val}'
)

$ echo $pctd 
11.1
$ echo $pid
1234
$ echo $proc 
process-name

更可靠的方式,是使用top

top -b -n1 | awk '/ PID /{p=1;next} p && !/top/{print $9, $12;exit}'

相关内容