1. 概念层面
ps -a
中的-a
是 BSD 风格选项(注意前面没有连字符时也是 BSD 风格)。
含义:
“Select all processes except both session leaders and processes not associated with a terminal.”
直译:选出「除了会话首进程(session leader)以及没有控制终端的进程」以外的所有进程。
典型场景:你在图形界面或 ssh 登录后敲ps -a
,会看到自己和别的用户跑在前台/后台、但仍有终端的程序,不会看到守护进程(daemon)、systemd、内核线程等。ps -e
中的-e
是标准 UNIX(POSIX)风格选项。
含义:
“Select every process on the system.”
直译:系统上每一个进程都列出来,不论有没有终端、是不是会话首进程、属于哪个用户。
典型场景:想一次性看包括 kthreadd、systemd、crond、dockerd 在内的全部进程时用它。
2. 实现差异(内核数据筛选逻辑)
procfs 里每个进程 /proc/PID/stat
的第 6 字段是 tty 设备号,ps
读取后:
-a
会过滤掉:
– 第 6 字段为 0(无控制终端)的 task;
– 第 5 字段(pgid)== 第 4 字段(pid)的 task(即 session leader);-e
不做任何过滤。
3. 实际输出对比(实验验证)
打开两个终端做实验:
# 终端 A:后台跑一个无终端的 sleep
nohup sleep 1000 &
# 终端 B:跑一个前台 sleep
sleep 2000
# 再开一个终端 C 做观察
ps -a | grep sleep
# 输出只有一行:PID 为 2000 的那个(带 pts/?)
ps -e | grep sleep
# 输出两行:1000 和 2000 都在
结论:-a
把 nohup
启动的无终端进程过滤掉了。
再看守护进程:
ps -a | wc -l # 通常几十行
ps -e | wc -l # 通常几百行
4. 常见误区与补充
误区 1:
-a
只会显示“当前用户”的进程?
错。-a
会显示所有用户的进程,只是排除了无终端/会话首进程,因此如果你切到 root 再跑ps -a
,依旧看不到 crond、sshd 等 daemon。误区 2:
-A
与-e
是否不同?
在 Linux 的 procps-ng 实现中,-A
与-e
完全等价,只是 POSIX 标准保留了-e
,BSD 风格习惯用-A
。补充:想要带完整格式可以组合
-f
(full-format):
ps -ef
等价于ps -e -f
,最常用;
ps -af
则仍然是“有终端且非会话首进程”的精简集合。
一句话总结
ps -a
把「无终端进程 + 会话首进程」剔掉,等于“有人机交互痕迹的进程”;
ps -e
一个不落地把系统里所有 task 全拎出来。