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 時間的累積使用百分比。