1. 概述
ps 命令(“process status”的简称)用于显示和监控当前正在运行的进程
2. 命令语法
ps语法如下:
ps [options]
$ ps
PID TTY TIME CMD
14900 pts/1 00:00:00 bash
14925 pts/1 00:00:00 ps
默认情况下,它会以四列的形式打印当前用户和终端的进程:
- PID – 进程ID
- TTY – 进程关联的终端
- TIME – 进程的累计CPU使用时间
- CMD – 执行的命令
3. 基础用法
3.1. 列出所有进程
使用 -e 可打印系统中的所有进程,而不仅仅是当前终端的进程:
$ ps -e
PID TTY TIME CMD
1 ? 00:00:25 systemd
2 ? 00:00:00 kthreadd
3 ? 00:00:00 rcu_gp
...
我们还可以 使用 -f 查看更详细的输出:
$ ps -e -f
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Feb11 ? 00:00:26 /usr/lib/systemd/systemd --switched-root --system --deserialize 28
root 2 0 0 Feb11 ? 00:00:00 [kthreadd]
root 3 2 0 Feb11 ? 00:00:00 [rcu_gp]
...
每一列的含义:
- UID – 进程所有者的用户ID
- PPID – 父进程ID(在这个特定的片段中,rcu_gp 是由 kthread 派生的)
- C – CPU使用率百分比
- STIME – 进程的启动时间
此外,当 ps 能够识别进程参数时,它还会在 CMD 列中打印这些参数。
3.2. 搜索过滤
使用 -C 选项按名称搜索特定进程:
$ ps -C systemd
PID TTY TIME CMD
1 ? 00:00:06 systemd
1658 ? 00:00:00 systemd
注意,我们使用完整的进程可执行文件名,而不是子字符串。
此外,ps 还允许我们 使用 -p 根据进程 ID 列表进行过滤:
$ ps -p 1,1658
PID TTY TIME CMD
1 ? 00:00:06 systemd
1658 ? 00:00:00 systemd
使用 -u 按用户名搜索:
$ ps -u root
PID TTY TIME CMD
1 ? 00:00:08 systemd
2 ? 00:00:00 kthreadd
3 ? 00:00:00 rcu_gp
...
这里有一个特别需要注意的地方,我们将在下一节详细解释。
4. 高级用法
4.1. 显示线程
使用-L
参数,列出指定进程创建的线程:
$ ps -C gedit -L
PID LWP TTY TIME CMD
12050 12050 ? 00:00:02 gedit
12050 12051 ? 00:00:00 gmain
12050 12052 ? 00:00:00 gdbus
12050 12054 ? 00:00:00 dconf worker
-C
按进程名称进行过滤,这里搜索名为 "gedit" 的进程。
LWP 列表示线程ID。
如果我们想要更多的输出,可结合-f
使用:
$ ps -C gedit -L -f
UID PID PPID LWP C NLWP STIME TTY TIME CMD
user 12050 1658 12050 0 4 21:36 ? 00:00:03 /usr/bin/gedit --gapplication-service
user 12050 1658 12051 0 4 21:36 ? 00:00:00 /usr/bin/gedit --gapplication-service
user 12050 1658 12052 0 4 21:36 ? 00:00:00 /usr/bin/gedit --gapplication-service
user 12050 1658 12054 0 4 21:36 ? 00:00:00 /usr/bin/gedit --gapplication-service
NLWP 列表示 进程的总线程数。
4.2. 列出子进程
如需 查看衍生的子进程 而不是线程。我们可以 使用 -H 选项:
$ ps -e -H
PID TTY TIME CMD
...
2493 ? 00:01:36 firefox
2562 ? 00:00:03 Web Content
2614 ? 00:00:09 WebExtensions
2688 ? 00:00:32 Web Content
2730 ? 00:00:33 Web Content
2949 ? 00:00:09 Web Content
...
在这个特定的例子中,我们可以看到系统中所有进程的层次结构。不幸的是,我们无法直接通过进程ID或进程名称进行过滤。
然而,我们可以通过会话ID(SID)进行过滤。要获取会话ID,我们需要修改 ps 命令的输出方式。我们将在下一节详细解释这是如何工作的。
首先,让我们获取我们进程的会话ID:
$ ps -C firefox -o pid,sid,cmd
PID SID CMD
2493 1874 /usr/lib64/firefox/firefox
然后,我们可以使用 -g 标志按 SID 进行过滤,以获得更小的输出:
$ ps -g 1874 -H
PID TTY TIME CMD
2125 ? 00:00:00 ibus-x11
1874 ? 00:00:46 gnome-shell
1919 ? 00:00:20 Xwayland
2116 ? 00:00:02 ibus-daemon
2122 ? 00:00:00 ibus-dconf
2123 ? 00:00:00 ibus-extension-
2214 ? 00:00:01 ibus-engine-sim
2493 ? 00:01:58 firefox
2562 ? 00:00:04 Web Content
2614 ? 00:00:10 WebExtensions
2688 ? 00:00:36 Web Content
2730 ? 00:00:36 Web Content
2949 ? 00:00:09 Web Content
让我们仔细看看这个输出。会话ID等于启动该会话的进程ID — 也称为会话leader。在这个例子中,会话领导者是 gnome-shell 进程。
会话leader衍生了几个子进程,包括我们感兴趣的进程。现在我们可以在树状视图输出中看到它们。
4.3. 控制输出
到目前为止,我们只看到了默认输出和详细输出。在某些情况下这并不是很有帮助,特别是当我们想要使用其他工具(如 read命令)自动处理 ps 的输出时。
我们可以使用 -o 标志来控制打印哪些列:
$ ps -C gedit -L -o pid,lwp,time,comm
PID LWP TIME COMMAND
12050 12050 00:00:03 gedit
12050 12051 00:00:00 gmain
12050 12052 00:00:00 gdbus
12050 12054 00:00:00 dconf worker
我们还可以 控制打印这些列的顺序:
$ ps -C gedit -L -o lwp,comm,time,pid
LWP COMMAND TIME PID
12050 gedit 00:00:03 12050
12051 gmain 00:00:00 12050
12052 gdbus 00:00:00 12050
12054 dconf worker 00:00:00 12050
ps 命令支持大量的输出修饰符。要查看它们的完整描述,我们可以随时查阅 Linux 帮助手册。
由于修饰符很多,让我们只尝试一些比较有趣的:
$ ps -C gedit -o comm,pid,rss,pmem,stat,vsz
COMMAND PID RSS %MEM STAT VSZ
gedit 12050 63072 0.1 Sl 371060
让我们解释一下这个输出:
- RSS 表示使用的非交换物理内存,单位为千字节
- %MEM 是进程使用的物理内存百分比(RSS 与系统总物理内存的比率)
- STAT 是多字符进程状态(在这种情况下,进程是多线程的并且处于可中断睡眠状态)
- VSZ 表示进程的虚拟内存大小,单位为KiB
4.4. 有效用户名和真实用户名
还记得我们之前讨论过按用户名过滤吗?
说到进程,在Linux中,我们区分两种类型的用户名:真实用户名和有效用户名。
真实用户名是启动进程的用户。有效用户是拥有该进程背后可执行文件的用户。
让我们在另一个终端中运行passwd工具,并让它等待我们的提示:
$ passwd
Changing password for user.
Current password:
现在,让我们看看如果我们用 ps 打印出真实和有效用户名会发生什么:
$ ps -C passwd -o pid,tty,ruser,user,cmd
PID TT RUSER USER CMD
12503 pts/2 user root passwd
真实用户与有效用户不同。这是因为 passwd 归 root 所有,但是被我们的 user 调用。
这种特殊行为适用于兼容 setuid 的可执行文件。它发生在当前用户需要以临时提升的权限运行程序时。
ps 命令可以使用 -U 选项按真实用户名过滤,也可以使用 -u 选项按有效用户名过滤。
5. 结论
在这个快速教程中,我们学习了如何使用 ps 命令。
我们首先介绍了按名称、进程 ID 和用户过滤进程的基础知识。然后,我们深入探讨了进程树和线程等高级主题。
最后,我们探索了如何自定义输出,并解释了不同类型的用户名。