PS 命令

登录信息

w
 13:46:05 up 3 days, 16:15,  2 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    120.231.138.139  13:43    1.00s  0.00s  0.00s w
kuga     pts/1    120.231.138.139  13:44   53.00s  0.02s  0.02s -bash

下面执行的命令都是基于以上的环境配置。

进程状态

PS 全称是 Process Status。

man ps
ps - report a snapshot of the current processes.
风格来源前缀
Unix贝尔实验室的 AT&T 系统-
BSD伯克利软件发行版
GNUGNU 组织的改进版本--

因为历史的原因 ps 命令混杂着各种不同的风格,有时候确跟 💩 一样。

不添加任何选项

ps
    PID TTY          TIME CMD
  20274 pts/0    00:00:00 bash
  20714 pts/0    00:00:00 sleep
  20715 pts/0    00:00:00 ps

不添加任何选项时,它会显示所有与当前终端相关的进程。 简单来说,如果当前终端的 TTY 是 pts/0,那么他会显示所有 TTY 是 pts/0 的进程。 通常包括 Shell 进程、从这个终端启动的任何进程(无论是前台还是后台),以及 ps 命令本身。 上面的 sleep 进程是我使用后台进程的方式启动的。

nohup sleep 60 &

基础选项

选项:a

显示与终端相关的所有进程,不仅仅是当前终端或当前用户。

ps a
    PID TTY      STAT   TIME COMMAND
    821 ttyS0    Ss+    0:00 /sbin/agetty -o -p -- \u --keep-baud 115200,57600,38400,9600 ttyS0 vt220
    845 tty1     Ss+    0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
  23300 pts/0    Ss     0:00 -bash
  23393 pts/1    Ss+    0:00 -bash
  23475 pts/0    R+     0:00 ps a

上面的结果是从 pts/0 终端执行的,可以看到,终端为 ttyS0tty1pts/1 的进程都显示出来了, 也没有区分用户,pts/0ttyS0tty1 是 root 的,pts/1 是 kuga 的。

选项:u

以用户友好的格式显示进程信息。

ps u
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         821  0.0  0.0   5800  1092 ttyS0    Ss+  Aug07   0:00 /sbin/agetty -o -p -- \u --keep-baud 115200,57600,3
root         845  0.0  0.0   6176  1072 tty1     Ss+  Aug07   0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
root       23300  0.0  0.3   8792  5616 pts/0    Ss   13:43   0:00 -bash
root       23480  0.0  0.0  10072  1588 pts/0    R+   14:01   0:00 ps u

如果这个选项只跟显示字段有关,那它的进程集应该和没有添加任何选项的 ps 命令一样。 然而上面的结果表明,除了自身终端 pts/0 的进程,它也显示了别的终端进程, 但它没有显示 pts/1 的终端进程(用户是 kuga)。

可以简单得出结论,u 选项的进程集就是:与当前用户终端相关的所有进程。 上面就是与 root 用户相关的所有终端进程,如果在 kuga 用户的终端执行 ps u, 可以得到下面的结果,完全符合预期。

ps u
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
kuga       23393  0.0  0.3   8660  5452 pts/1    Ss   13:44   0:00 -bash
kuga       23496  0.0  0.0  10072  1608 pts/1    R+   14:22   0:00 ps u

另外这个进程集的定义不是 u 选项特有的,它和 BSD 风格有关。

选项:x

显示属于当前用户的所有进程。

ps x
    PID TTY      STAT   TIME COMMAND
  23330 ?        Ss     0:00 /lib/systemd/systemd --user
  23331 ?        S      0:00 (sd-pam)
  23392 ?        R      0:00 sshd: kuga@pts/1
  23393 pts/1    Ss     0:00 -bash
  23719 pts/1    R+     0:00 ps x

上面的结果是在 kuga 用户的终端执行的,所以进程数量不会太多。

选项:-e

显然所有进程。

man ps | grep "\-e  "
-e     Select all processes.  Identical to -A.

选项:-f

以全格式(full-format)显示进程信息,可以与其他 UNIX-style 的选项组合使用。

man ps | grep "\-f  "
-f     Do full-format listing.  This option can be combined with many other UNIX-style options to add

ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
root       23300   23163  0 13:43 pts/0    00:00:00 -bash
root       24317   23300  0 16:53 pts/0    00:00:00 ps -f

选项:-o

自定义输出字段,不能与 -fu 选项共用。

ps -o uid,user,pid,%cpu,%mem,cmd
UID USER   PID %CPU %MEM CMD
  0 root 23300  0.0  0.3 -bash
  0 root 24311  0.0  0.0 ps -o uid,user,pid,%cpu,%mem,cmd

注意这里的 uid 和使用 -f 选项显示的内容不一样,这里是数字 ID,但 -f 会显示用户名。

选项:-p

指定进程 PID。

ps up 1
USER  PID %CPU %MEM    VSZ   RSS TTY  STAT START   TIME COMMAND
root    1  0.0  0.7 167696 13328 ?    Ss   Aug07   0:08 /lib/systemd/systemd --system --deserialize 36 noib

选项:--forest

以 ASCII 显示进程与子进程的树状结构。

man ps | grep -A 1 "\--forest"
--forest
       ASCII art process tree.

ps -o pid,ppid,cmd --forest
    PID    PPID CMD
  23300   23163 -bash
  24537   23300  \_ ps -o pid,ppid,cmd --forest

不同风格的进程集

不同风格的选项进程集是不一样的,但只要细心观察,还是能发现一些规律。

ps:不添加任何选项

ps
    PID TTY          TIME CMD
   2090 pts/0    00:00:00 bash
   2261 pts/0    00:00:00 ps

ps -l:Unix 风格,-l 表示以长格式显示。

ps -l
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0    2090    2034  0  80   0 -  2198 do_wai pts/0    00:00:00 bash
4 R     0    2262    2090  0  80   0 -  2518 -      pts/0    00:00:00 ps

ps l:BSD 风格,l 表示以 BSD 长格式显示。

ps l
F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4     0     760       1  20   0   5800  1160 do_sel Ss+  ttyS0      0:00 /sbin/agetty -o -p -- \u --keep-baud 115200,57600,38400,9600 ttyS0 vt220
4     0     779       1  20   0   6176  1108 do_sel Ss+  tty1       0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
4     0    2090    2034  20   0   8792  5492 do_wai Ss   pts/0      0:00 -bash
4     0    2298    2090  20   0  10072  1608 -      R+   pts/0      0:00 ps l

ps --forest:GNU 风格,--forest 表示以进程树的方式显示。

ps --forest
    PID TTY          TIME CMD
   2090 pts/0    00:00:00 bash
   2316 pts/0    00:00:00  \_ ps

上面的例子中,所用的选项都是和进程集无关的,可以总结出如下规律:

风格进程集
无选项显示所有与当前终端相关的进程
Unix与不添加选项一致
BSD显示与当前用户终端相关的所有进程
GNU与不添加选项一致

显然,Unix 和 GNU 风格看上去更符合逻辑,因为它们的进程集和不添加选项时的进程集是一样的, 但 BSD 风格就自己加戏了,把当前用户其他终端相关的进程也包含进来了。 不同风格的选项可以一起使用,但如果两个选项都是指定显示格式,会无法执行。 另外,如果多个风格中包含了 BSD 风格,但选项中又没有指定进程集,那么默认会使用 BSD 的进程集。

常用功能

列出用户进程

ps -fu kuga

列出所有进程

ps -ef

-e 显示所有进程,-f 以全格式显示,这没什么好说的。

ps aux

奇怪的是 aux 的进程集,从上面的分析可以知道:

  • a:显示与终端相关的所有进程,不仅仅是当前终端或当前用户。
  • x:显示属于当前用户的所有进程。

显然 ax 加起来也只是当前用户的所有进程和不区分用户的所有终端进程,但如果再看一下官方的文档。

a ... or to list all processes when used together with the x option.
x ... or to list all processes when used together with the a option.

ax 一起用的时候代表所有进程,我们也可以验证一下进程数。

ps aux | wc -l
ps -ef | ec -l

可以看到 aux-ef 的进程集数量是一样的,我很细节的,我说的是数量🤪。

占用内存排名

go rocks

特殊字段说明

VSZ

Virtual Memory Size,虚拟内存大小,以 KB 为单位。

RSS

Resident Set Size,常驻内存大小,以 KB 为单位。

TTY

进程关联的终端。如果进程与某个终端关联,它会显示终端的名称;如果未关联终端,则显示 ?

STAT

进程的状态码。常见的状态码包括:

  • R: 运行中(Running)。
  • S: 睡眠中(Sleeping),等待某个事件完成。
  • D: 不可中断的睡眠状态(Uninterruptible Sleep),通常是等待 I/O。
  • T: 暂停或跟踪中(Stopped or Traced)。
  • Z: 僵尸进程(Zombie),进程已经终止,但未被父进程清理。
  • I: 空闲内核线程(Idle Kernel Thread)。
  • Ss: 主进程处于睡眠状态。
  • R+: 运行中的进程,并且在前台显示。

go rocks 需要深入理解不同的进程状态

START

进程启动的时间或日期。对于新进程,显示的是时间,对于旧进程,显示的是日期。

TIME

进程使用 CPU 的累计时间,表示该进程总共占用了多少 CPU 时间。

C

进程的 CPU 使用率。这个字段显示的是自进程启动以来,CPU 时间的累积使用百分比。