Skip to content

从0到1搞懂 Linux ps 命令

1. 一句话说清楚

ps(Process Status)是 Linux 中用于查看当前系统进程快照的命令——它拍的是"此刻"进程的照片,而不是实时监控视频。

生活类比ps 就像体检时的一张 X 光片——它抓住的是你按快门那一瞬间身体(系统)里所有器官(进程)的状态。想要持续观察心跳(实时监控),得换心电监护仪(top / htop)。


2. 为什么需要它

2.1 它解决了什么痛点?

在 Linux 中,一切皆文件,一切工作皆进程。没有 ps,你就像蒙着眼睛管理一座工厂——不知道有多少工人在干活、谁在摸鱼、谁已经"死"了还占着工位(僵尸进程)。

场景没有 ps 你得怎么做有了 ps
找到某个占用 CPU 的进程手动翻 /proc 目录下成百上千的文件ps aux --sort=-%cpu | head
杀掉卡死的程序不知道 PID,无从下手ps -C nginx -o pid= 拿到 PID 再 kill
查看进程的父子关系逐个读 /proc/[pid]/statusps -ejHps axjf 看进程树
排查僵尸进程遍历 /proc 逐个检查状态ps aux | grep Z

2.2 适用场景

  • 快速诊断:查看某个服务是否在运行
  • 排障分析:找到 CPU/内存占用高的进程
  • 脚本编程:在 Shell 脚本中获取 PID 做自动化处理
  • 安全审计:检查是否有异常进程运行
  • 进程关系梳理:查看父子进程、会话、进程组

2.3 什么时候不该用它?

  • 需要实时持续监控 → 用 tophtopatop
  • 需要追踪进程的系统调用 → 用 strace
  • 需要查看网络连接与进程的关系 → 用 ss -pnetstat -p
  • 需要历史进程分析 → 用 sarpidstat 等性能工具

3. 核心概念与原理

3.1 ps 的数据来源:/proc 文件系统

ps 并不是向内核发送特殊的系统调用,而是读取 /proc 虚拟文件系统/proc 是内核在内存中维护的一个伪文件系统,每个正在运行的进程都有一个以 PID 命名的目录:

text
/proc/
├── 1/              ← PID=1 的进程(通常是 init/systemd)
│   ├── status      ← 进程状态信息
│   ├── cmdline     ← 启动命令行
│   ├── stat        ← 进程统计数据(机器可读)
│   ├── fd/         ← 打开的文件描述符
│   └── ...
├── 1234/           ← PID=1234 的进程
│   └── ...
├── meminfo         ← 系统内存信息
├── cpuinfo         ← CPU 信息
└── ...

为什么这样设计? 将进程信息暴露为文件系统接口,让任何程序(不仅是 ps)都能通过标准的文件读取 API 获取进程数据,无需特殊的内核接口。这是 Linux "一切皆文件" 哲学的体现。

3.2 三种选项风格

ps 命令历史悠久,融合了多种 Unix 变体的风格,这也是它最让人困惑的地方:

图解说明ps 的三种选项风格来自不同的 Unix 历史分支。千万不要混用!比如 ps -auxps aux 的含义是完全不同的(后面会详细说明)。

3.3 进程状态模型

Linux 内核中每个进程都处于以下状态之一:

图解说明:这张状态转换图展示了一个进程从创建到消亡的完整生命周期。psSTAT 列输出的就是进程当前所处的状态。


4. 关键机制详解

4.1 进程选择:决定"看哪些进程"

是什么ps 默认只显示当前用户、当前终端关联的进程。通过进程选择选项可以扩大或缩小显示范围。

怎么工作

选项含义等价写法
-e / -A选择所有进程
-a所有带终端的进程(排除会话首进程)
a (BSD)解除"仅限自己"的限制
x (BSD)解除"必须有终端"的限制
-u userlist按有效用户选择U userlist (BSD)
-p pidlist按 PID 选择--pid pidlist
-C cmdlist按命令名称选择
--ppid pidlist按父进程 PID 选择
-t ttylist按终端选择

示例

bash
# 查看所有进程(Unix 风格 — 最常用)
ps -ef

# 查看所有进程(BSD 风格 — 最常用)
ps aux

# 只查看 nginx 相关的进程
ps -C nginx -o pid,ppid,stat,cmd

# 查看 PID 为 1 和 1234 的进程
ps -p 1,1234 -o pid,ppid,cmd

# 查看某个用户的所有进程
ps -u www-data

⚠️ 注意事项

ps -auxps aux 这是最经典的陷阱。

  • ps aux(BSD 风格):显示所有用户的所有进程,这是你想要的。
  • ps -aux(Unix 风格):-a 选择带终端进程,-u 按用户名 x 筛选。如果系统没有用户名叫 x,ps 会"好心"地忽略错误并按 ps aux 执行,但这是不可靠的行为

结论:用 ps auxps -ef,不要用 ps -aux

4.2 输出格式:决定"看哪些列"

是什么:控制 ps 输出哪些字段(列),有预设格式和自定义格式两种方式。

预设格式对比

bash
# 简单格式(默认)
ps
#  PID TTY          TIME CMD
# 12345 pts/0    00:00:00 bash

# 完整格式 -f
ps -ef
# UID   PID  PPID  C STIME TTY    TIME CMD
# root    1     0  0 Mar25 ?   00:00:03 /sbin/init

# 额外完整格式 -F(比 -f 多 SZ、RSS、PSR 列)
ps -eF

# BSD 用户格式 u
ps aux
# USER  PID %CPU %MEM   VSZ  RSS TTY  STAT START TIME COMMAND
# root    1  0.0  0.1 16.9M 10M ?    Ss   Mar25 0:03 /sbin/init

# 长格式 -l
ps -el
# F S UID  PID PPID  C PRI NI ADDR SZ WCHAN TTY  TIME CMD

自定义格式 -o:最灵活强大的方式:

bash
# 自定义显示:PID、用户、CPU占比、内存占比、状态、命令
ps -eo pid,user,%cpu,%mem,stat,cmd

# 自定义列名(用 = 号重命名)
ps -eo pid=进程ID,user=用户,%cpu=CPU占比,cmd=命令

# 指定列宽(用 :宽度)
ps -eo pid,wchan:20,cmd

# 只输出值、不输出表头(将表头设为空)
ps -C sshd -o pid=

常用格式说明符速查

说明符表头含义
pidPID进程 ID
ppidPPID父进程 ID
userUSER有效用户名
%cpu%CPUCPU 使用率(生命周期平均)
%mem%MEM物理内存使用百分比
vszVSZ虚拟内存大小(KB)
rssRSS常驻内存大小(KB)
statSTAT进程状态(多字符)
startSTARTED进程启动时间
timeTIME累计 CPU 时间
cmd / argsCMD完整命令行
commCOMMAND命令名(仅可执行文件名)
ttyTT控制终端
niNInice 值(优先级调整)
priPRI优先级
wchanWCHAN进程睡眠时所在的内核函数
lwpLWP线程 ID
nlwpNLWP线程数

4.3 STAT 状态码:读懂进程的"健康报告"

是什么STAT 列是进程当前状态的缩写编码,由一个主状态码 + 多个修饰符组成。

主状态码

代码英文含义中文解释类比
RRunning / Runnable正在运行或在运行队列中等待 CPU正在工位上干活 / 排队等工位
SInterruptible Sleep可中断睡眠,等待某个事件在休息室打盹,有人叫就醒
DUninterruptible Sleep不可中断睡眠,通常在做磁盘 I/O戴着降噪耳机专注搬砖,谁叫都不理
TStopped被信号停止被领导喊"暂停"了
tTracing stop被调试器暂停(如 gdb)被质检员拦住检查
ZZombie僵尸进程,已终止但父进程未回收人走了,工牌还没注销
IIdle空闲内核线程内核里待命的后勤人员
XDead已死亡(正常看不到)理论上不该出现

修饰符(附加在主状态码后面):

修饰符含义示例
<高优先级(nice 值 < 0)R< = 高优先级运行中
N低优先级(nice 值 > 0)SN = 低优先级睡眠
L有内存页被锁定SlSL 注意区分
s会话首进程(session leader)Ss = 睡眠的会话首进程
l多线程Sl = 睡眠的多线程进程
+在前台进程组中R+ = 前台运行中

读懂实际输出

bash
$ ps aux | head -5
USER   PID %CPU %MEM    VSZ   RSS TTY  STAT START   TIME COMMAND
root     1  0.0  0.1  16940 10240 ?    Ss   Mar25   0:03 /sbin/init
root     2  0.0  0.0      0     0 ?    S    Mar25   0:00 [kthreadd]
root   857  0.2  1.5 723456 62720 ?    Ssl  Mar25   2:15 /usr/bin/dockerd
user  1500  0.0  0.2 224000 10240 pts/0 S+   10:30  0:00 vim myfile.txt
  • Ss:可中断睡眠 + 会话首进程(init 通常是这个状态)
  • S:普通可中断睡眠
  • Ssl:可中断睡眠 + 会话首进程 + 多线程(Docker daemon 典型状态)
  • S+:可中断睡眠 + 前台进程(vim 在前台编辑文件)

4.4 排序与过滤:精准定位问题进程

是什么ps 支持按任意字段排序输出,结合管道可以快速找到"问题进程"。

内置排序 --sort

bash
# 按 CPU 使用率降序排列(- 表示降序)
ps aux --sort=-%cpu | head -10

# 按内存使用率降序排列
ps aux --sort=-%mem | head -10

# 多字段排序:先按用户升序,再按 CPU 降序
ps aux --sort=user,-%cpu

# 按启动时间排序
ps -eo pid,lstart,cmd --sort=-lstart | head -10

结合管道过滤

bash
# 查找特定进程(经典用法)
ps aux | grep nginx | grep -v grep

# 更优雅的方式:用 -C 直接按命令名筛选
ps -C nginx -o pid,ppid,stat,%cpu,%mem,cmd

# 查找僵尸进程
ps aux | awk '$8 ~ /Z/'

# 找到占用内存最多的 10 个进程
ps -eo pid,user,%mem,rss,cmd --sort=-%mem | head -11

⚠️ 注意事项

  • %cpu 是进程整个生命周期的 CPU 平均使用率,不是"此刻"的。如需实时 CPU 占用,用 toppidstat
  • ps aux | grep xxx 会把 grep 本身也匹配出来,要么加 grep -v grep,要么用 ps -C xxx 替代。

4.5 进程树:看清父子关系

是什么:以树状结构展示进程的层级关系,一目了然地看出谁创建了谁。

怎么用

bash
# Unix 风格:进程层级
ps -ejH

# BSD 风格:ASCII 艺术树
ps axjf

# GNU 风格
ps -e --forest

# 自定义格式 + 树状显示
ps -eo pid,ppid,user,stat,cmd --forest

# 只看某个进程及其子进程树
ps --forest -o pid,ppid,cmd -g $(ps -C sshd -o sid= | head -1)

输出示例

text
  PID  PPID USER     STAT CMD
    1     0 root     Ss   /sbin/init
  456     1 root     Ss    \_ /usr/sbin/sshd -D
 1200   456 root     Ss        \_ sshd: user [priv]
 1210  1200 user     S             \_ sshd: user@pts/0
 1211  1210 user     Ss                \_ -bash
 1300  1211 user     R+                    \_ ps --forest -o pid,ppid,user,stat,cmd

小技巧:如果只想看某个进程的树状关系,pstree 命令比 ps --forest 更直观:pstree -p 456


5. 动手实践

5.1 实践一:排查 CPU 占用 Top 10

目标:找出当前系统中 CPU 占用最高的 10 个进程。

前置准备:任何 Linux 系统都自带 ps,无需安装。

运行步骤

bash
# 方法1:BSD 风格 + 排序
ps aux --sort=-%cpu | head -11

# 方法2:自定义格式,更清晰
ps -eo pid,user,%cpu,%mem,stat,start,time,cmd --sort=-%cpu | head -11

预期输出

text
  PID USER     %CPU %MEM STAT  STARTED     TIME CMD
 2345 mysql     5.2  8.3 Ssl  Mar 25 01:23:45 /usr/sbin/mysqld
  857 root      0.2  1.5 Ssl  Mar 25 00:02:15 /usr/bin/dockerd
 1100 www-data  0.1  0.8 S    Mar 25 00:00:30 nginx: worker process
  ...

解读

  • %CPU 列:进程生命周期内的 CPU 平均使用率
  • 第一行(排除表头)就是 CPU 占用最高的进程
  • Ssl 表示该进程处于可中断睡眠、是会话首进程且是多线程的

5.2 实践二:排查僵尸进程

目标:找到系统中的僵尸进程,并定位其父进程。

运行步骤

bash
# 第一步:查看是否有僵尸进程
ps aux | awk 'NR==1 || $8 ~ /Z/'

# 第二步:如果有,查看僵尸进程的父进程
# 假设僵尸进程的 PID 是 9999
ps -o pid,ppid,stat,cmd -p 9999

# 第三步:查看父进程信息
# 假设 PPID 是 8888
ps -o pid,ppid,stat,cmd -p 8888

# 一步到位:找出所有僵尸进程及其父进程
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/ {print}' | while read pid ppid stat cmd; do
    echo "僵尸进程: PID=$pid, 父进程PID=$ppid"
    echo "  父进程详情: $(ps -o pid,cmd= -p $ppid 2>/dev/null)"
done

预期输出(存在僵尸进程时)

text
USER   PID  %CPU %MEM VSZ  RSS TTY STAT START TIME COMMAND
root   9999  0.0  0.0    0   0  ?  Z    10:30 0:00 [myapp] <defunct>

解读

  • Z 状态 + <defunct> 标记 = 僵尸进程
  • VSZ 和 RSS 都是 0,因为僵尸进程已经释放了内存,只是在进程表中留了一个条目
  • 解决办法:让父进程调用 wait() 回收,或杀掉父进程让 init 接管回收

5.3 实践三:监控脚本——每 5 秒保存进程快照

目标:编写一个简单的监控脚本,定期保存进程快照用于事后分析。

bash
#!/bin/bash
# process_snapshot.sh - 每5秒保存一次进程快照
LOG_DIR="/tmp/ps_snapshots"
mkdir -p "$LOG_DIR"

echo "开始记录进程快照到 $LOG_DIR ..."
echo "按 Ctrl+C 停止"

while true; do
    TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
    OUTPUT_FILE="$LOG_DIR/ps_$TIMESTAMP.log"
    
    echo "=== 快照时间: $(date) ===" > "$OUTPUT_FILE"
    echo "" >> "$OUTPUT_FILE"
    
    echo "--- Top 10 CPU ---" >> "$OUTPUT_FILE"
    ps -eo pid,user,%cpu,%mem,stat,cmd --sort=-%cpu | head -11 >> "$OUTPUT_FILE"
    echo "" >> "$OUTPUT_FILE"
    
    echo "--- Top 10 Memory ---" >> "$OUTPUT_FILE"
    ps -eo pid,user,%cpu,%mem,rss,cmd --sort=-%mem | head -11 >> "$OUTPUT_FILE"
    echo "" >> "$OUTPUT_FILE"
    
    echo "--- 僵尸进程 ---" >> "$OUTPUT_FILE"
    ps aux | awk 'NR==1 || $8 ~ /Z/' >> "$OUTPUT_FILE"
    
    echo "已保存: $OUTPUT_FILE"
    sleep 5
done

运行

bash
chmod +x process_snapshot.sh
./process_snapshot.sh

6. 横向对比

6.1 ps vs 同类进程查看工具

特性pstophtoppidstatpstree
类型快照(一次性)实时监控实时监控(增强)定期采样统计快照(树形)
安装系统自带系统自带需安装需装 sysstat需安装
输出定制⭐⭐⭐ 极强(-o)⭐⭐ 一般⭐⭐ 一般⭐⭐ 较强⭐ 有限
实时刷新✅(间隔采样)
进程树✅ (--forest)✅ (F5)✅(专业)
线程查看✅ (-L, -T)✅ (H)✅ (-t)✅ (-t)
CPU 精度生命周期平均实时(刷新间隔)实时采样间隔平均
脚本友好⭐⭐⭐ 非常好⭐ batch 模式⭐ 较差⭐⭐ 较好⭐ 一般
适用场景脚本/一次性查看交互式监控交互式监控性能分析查看进程层级

6.2 ps -ef vs ps aux:该用哪个?

对比项ps -ef (Unix/System V)ps aux (BSD)
风格Unix 标准BSD 风格
特有列PPID(父进程 ID)、STIME%CPU、%MEM、VSZ、RSS、STAT
命令列CMD(完整命令行)COMMAND(完整命令行)
适合场景需要看父子关系时需要看资源占用时
可移植性POSIX 标准,更通用大多数 Linux 支持

建议

  • 日常排查资源问题 → ps aux(有 CPU、内存信息)
  • 排查进程关系 → ps -ef(有 PPID)
  • 脚本中追求可移植性 → ps -ef

7. 高频使用速查表

整理日常工作中最常用的 ps 命令组合:

bash
# ========== 基础查看 ==========
ps -ef                          # 查看所有进程(Unix 格式,含 PPID)
ps aux                          # 查看所有进程(BSD 格式,含 CPU/MEM)
ps -u username                  # 查看某用户的进程
ps -p 1234                      # 查看指定 PID 的进程
ps -C nginx                     # 按命令名查找进程

# ========== 资源排序 ==========
ps aux --sort=-%cpu | head      # CPU 占用 Top 10
ps aux --sort=-%mem | head      # 内存占用 Top 10
ps aux --sort=-rss | head       # 常驻内存 Top 10

# ========== 进程树 ==========
ps -ejH                         # 进程树(Unix 风格)
ps axjf                         # 进程树(BSD 风格)
ps -eo pid,ppid,cmd --forest    # 自定义格式 + 树

# ========== 线程查看 ==========
ps -eLf                         # 查看所有线程
ps -L -p 1234                   # 查看某进程的线程
ps -eo pid,nlwp,cmd | sort -k2 -rn | head  # 线程数 Top 10

# ========== 排障专用 ==========
ps aux | awk '$8 ~ /Z/'         # 查找僵尸进程
ps aux | awk '$8 ~ /D/'         # 查找 D 状态(不可中断睡眠)进程
ps -C sshd -o pid=              # 获取进程 PID(无表头,适合脚本)
ps -eo pid,lstart,cmd --sort=-lstart | head  # 最近启动的进程

# ========== 自定义输出 ==========
ps -eo pid,user,%cpu,%mem,vsz,rss,stat,start,time,cmd  # 完整自定义
ps -eo pid,ppid,pgid,sid,tty,cmd                        # 会话/进程组信息

8. 进阶路线与资源

8.1 学习路径

text
入门                    进阶                      精通
 │                       │                         │
 ├─ ps -ef / ps aux     ├─ -o 自定义格式           ├─ /proc 文件系统深入
 ├─ 管道组合 grep/awk   ├─ --sort 多字段排序       ├─ 内核进程调度原理
 ├─ 基本状态码 R/S/Z    ├─ 线程查看 -L/-T          ├─ cgroups 与命名空间
 └─ 找进程 PID          ├─ 进程树 --forest          ├─ 性能分析工具链
                         └─ 结合 watch 定期查看      └─ 编写进程监控系统

8.2 推荐资源

类型资源说明
📖 官方文档man psman7.org/ps最权威的参考,必读
📖 官方文档procps-ng 项目ps 命令的源码和文档
📚 经典书籍《Linux 命令行与 Shell 脚本编程大全》进程管理章节非常实用
📚 经典书籍《鸟哥的 Linux 私房菜》中文入门经典
📚 深入书籍《Linux 内核设计与实现》(Robert Love)理解进程调度原理
📚 深入书籍《深入理解 Linux 进程》系统性讲解 /proc 文件系统
🔧 实战工具htopatoppidstatps 的互补工具,实际工作中常配合使用

8.3 常见面试考点

  1. ps -efps aux 的区别是什么? → 选项风格不同,输出列不同(见 6.2 对比表)
  2. 进程的 D 状态是什么?如何排查? → 不可中断睡眠,通常是 I/O 等待;用 ps aux | awk '$8~/D/' 查找,cat /proc/<pid>/wchan 查看卡在哪个内核函数
  3. 什么是僵尸进程?如何清理? → 子进程退出但父进程没调用 wait() 回收;杀掉父进程让 init 回收,或修复父进程代码
  4. ps 输出的 %CPU 准确吗? → 不是实时值,是进程生命周期平均;需要实时值用 toppidstat 1
  5. 如何查看一个进程有多少线程?ps -o nlwp -p <pid>ls /proc/<pid>/task/ | wc -l
  6. VSZRSS 的区别? → VSZ 是虚拟内存总量(包含 swap 和共享库),RSS 是实际使用的物理内存
  7. 如何找到占用某个端口的进程?ps 本身做不到,用 ss -tlnp | grep :80lsof -i :80

总结ps 是 Linux 进程管理的基石命令。记住 ps aux 看资源、ps -ef 看关系、ps -o 自定义输出这三板斧,再配合 grepawksort 等管道工具,就能覆盖 90% 的日常排障场景。剩下的 10%,交给 tophtopstrace 等专业工具。