资讯动态

Serenity OS 的 ps 命令完全指南:进程列表、列格式定制与源码级解析

发布时间:2026/9/11 11:40:53 来源:尧图企业网站定制
Serenity OS 的 ps 命令完全指南进程列表、列格式定制与源码级解析【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity导读本文以 Serenity Operating System 内置的ps命令手册页Base/usr/share/man/man1/ps.md为主线完整讲解其命令行选项、列格式定制、进程筛选规则与实战示例同时结合 Userland/Utilities/ps.cpp、LibCore/ProcessStatisticsReader.cpp 与内核 SysFS 进程节点实现深入剖析ps的数据来源、过滤逻辑与内核接口。读完本文你将能够在 Serenity 终端中熟练使用ps完成从查看当前终端进程到按 PID / PPID / TTY / 用户精细筛选、自定义输出列与标题的全部场景并理解其从内核到用户态的完整数据链路。一、命令概览ps 是什么psprocess status用于列出系统中当前正在运行的进程。在 Serenity OS 中ps的默认行为是只列出当前 TTY终端关联的进程并为每个进程输出三项信息PIDprocess ID进程 IDTTY该进程所属的终端CMD调用该进程的命令行 / 进程名。对应源码中的默认列集合Userland/Utilities/ps.cpp#L317-L322TRY(columns.try_ensure_capacity(3)); TRY(add_default_column(ColumnId::ProcessId)); TRY(add_default_column(ColumnId::TTY)); TRY(add_default_column(ColumnId::Command));而ps -f完整格式则会额外输出 UID、PPID、STATE 等字段对应 ps.cpp#L306-L316 中注册的 9 列默认集合。二、命令语法$ ps [--version] [-a] [-A] [-e] [-f] [-o column-format] [-p pid-list] [--ppid pid-list] [-q pid-list] [-t tty-list] [-u user-list]从 ps.cpp#L211-L292 可以看到所有选项均由Core::ArgsParser解析其中-p、--ppid、-q、-t、-u、-o都复用了同一个模板函数make_list_option它会把参数值按逗号或空格切分为列表ps.cpp#L189-L209因此这些选项天然支持逗号分隔与空格分隔两种写法。三、选项详解3.1 进程范围选项选项说明源码对应-a考虑所有与某个 TTY 关联的进程而非仅当前 TTYps.cpp#L237 设置every_terminal_process_flag-A考虑所有进程包括无 TTY 的内核进程ps.cpp#L238 设置every_process_flag-e等价于-A同样显示所有进程ps.cpp#L239 明确注释 Equivalent to -A三者背后的过滤逻辑在 ps.cpp#L339-L353默认无任何筛选选项只保留process.tty this_pseudo_tty_name的进程即当前 TTY 的进程-a只要进程的 TTY 非空!process.tty.is_empty()就保留-A/-e跳过过滤分支直接保留全部进程包括tty为空的内核线程。3.2 完整格式选项-f-f指定完整格式输出。此时ps会为每个进程额外打印UID以解析后的用户名显示如root、anonPPID父进程 PIDSTATE线程状态Runnable、Sleeping、Selecting、Reading 等见下文STATE 列说明。此外完整格式还会追加PGID、SID与STIME三列见 ps.cpp#L306-L316 的 9 列注册使-f输出比手册描述更为丰富列含义UID以用户名形式呈现的所有者PID进程 IDPPID父进程 IDPGID进程组 IDSID会话 IDSTATE线程状态STIME进程启动时间TTY关联终端CMD进程名 / 命令行3.3 自定义列格式-o column-format-o允许完全自定义输出列。格式为一个或多个列格式描述符以逗号或空格分隔COLUMN_NAME[COLUMN_TITLE]COLUMN_NAME必须是以下合法列名之一对应 ps.cpp#L20-L29 的列描述表列名默认标题对齐方式输出内容uidUID左对齐所有者用户名username字段pidPID右对齐进程 IDppidPPID右对齐父进程 IDpgidPGID右对齐进程组 IDsidSID右对齐会话 IDstateSTATE左对齐首线程状态无线程时为ZombiestimeSTIME左对齐启动时间今天启动显示%H:%M否则显示%b%dttyTTY左对齐伪终端名无 TTY 时显示n/acmdCMD左对齐进程名注手册列出的列名集合为uid, pid, ppid, pgid, sid, state, tty, cmd源码实现中额外提供了手册未列出的stime列ps.cpp#L27、ps.cpp#L103-L111这属于对文档的合法扩展。COLUMN_TITLE用于替换列头名称可以为空指定非空标题如cmdCommand列头显示为Command指定空标题如cmd该列不显示表头如果所有列标题都为空则整个表头被省略对应 ps.cpp#L364-L372 的header_is_empty判断。解析非法列名时ps会输出Could not parse ... as a column format specifier并忽略该项ps.cpp#L241-L248格式解析函数parse_column_format_specifier位于 ps.cpp#L119-L135它按切分超过两个部分或未知列名都会报错。3.4 按 PID 筛选-p pid-list选择与给定 PID 中任意一个匹配的进程。pid-list为逗号或空格分隔的 PID 列表$ ps -p 1,42,1003.5 按父进程筛选--ppid pid-list选择 PPID 与给定 PID 中任意一个匹配的进程即这些进程的直接子进程$ ps --ppid 42在 ps.cpp#L256-L262 中--ppid与-p各自维护独立的列表parent_pid_list与pid_list过滤时分别与process.ppid、process.pid做contains_slow匹配ps.cpp#L343-L344。3.6 快速定位-q pid-list-q只考虑给定 PID 中确实存在的进程并且按pid-list给出的顺序输出而非默认的 PID 升序。其实现是独立的快速列表路径ps.cpp#L331-L338因此排序阶段会跳过默认的quick_sortps.cpp#L356-L357。注意-q不能与其他筛选选项-p、--ppid、-t、-u等组合使用。若同时指定ps会输出The -q option cannot be combined with other filtering options.并以退出码 1 结束ps.cpp#L294-L297。3.7 按终端筛选-t tty-list选择与给定终端之一关联的进程。tty-list支持两种写法短 TTY 名例如pts:0、tty:1完整设备路径例如/dev/pts/0、/dev/tty1。列表以逗号或空格分隔。parse_tty_pseudo_nameps.cpp#L158-L187负责把输入归一化为伪终端名pts:N→/dev/pts/N、tty:N→/dev/ttyN再通过stat获取设备号并与tty_stat_to_pseudo_nameps.cpp#L137-L149比对——主设备号 201 对应pts:主设备号 4 对应tty:据此生成短名用于匹配。无法解析的 TTY 输入会得到Could not parse ... as a TTY提示。3.8 按用户筛选-u user-list选择与给定 UID 或登录名匹配的进程。列表同样以逗号或空格分隔$ ps -u 0 # 按 UID $ ps -u root # 按登录名 $ ps -u root,anon解析逻辑在 ps.cpp#L279-L291先尝试把输入解释为数字 UIDto_numberuid_t失败则通过Core::Account::from_name(user, Read::PasswdOnly)从/etc/passwd解析登录名两者都失败时输出Could not find user ...: ...。3.9 其他选项--version打印版本信息后退出。四、实战示例4.1 显示所有进程完整格式$ ps -ef这是最常用的组合-e列出全部进程-f启用完整格式UID、PPID、PGID、SID、STATE、STIME、TTY、CMD。4.2 自定义列PID、状态与进程名$ ps -eo pid,state,cmd输出三列PID右对齐、STATE左对齐、CMD左对齐且不指定任何筛选选项——此时默认仍只显示当前 TTY 的进程只是列内容被自定义。若想对全部进程自定义列可写成ps -Aeo pid,state,cmd。4.3 重命名列标题$ ps -q 42 -o cmdCommand,state-q 42只显示 PID 42若存在-o cmdCommand,state第一列cmd的表头改名为Command第二列state保持默认标题STATE。4.4 完全隐藏表头$ ps -q 42 -o cmdcmd表示空标题由于这是唯一的列且标题为空整个表头被省略输出只有 PID 42 的进程名一行。4.5 组合筛选示例# 当前终端中属于 root 的进程 $ ps -u root # PID 1 的所有直接子进程 $ ps --ppid 1 # pts:0 终端上的全部进程 $ ps -t pts:0 # 查看多个指定 PID逗号分隔 $ ps -p 42,100五、STATE 列说明手册提到 STATE 取值如 Runnable、Sleeping、Selecting、Reading 等。从源码看线程级状态由内核维护Kernel/Tasks/Thread.h#L112-L120 定义了Invalid / Runnable / Running / Dying / Dead / Stopped / Blocked等基础状态而Sleeping、Selecting、Reading这类细分状态由Thread::state_string()在导出到/sys/kernel/processes时生成Kernel/FileSystem/SysFS/Subsystems/Kernel/Processes.cpp#L128ps读取首线程的状态作为整行 STATE若进程没有任何线程则直接显示Zombieps.cpp#L99-L102。六、源码级原理ps 的数据从哪来ps并不直接遍历内核进程链表而是通过内核 SysFS 虚拟文件系统读取一份 JSON 快照ps在启动时先pledge(stdio rpath tty)随后降级为pledge(stdio rpath)并unveil允许访问/sys/kernel/processes、/etc/timezone、/etc/passwd、/etc/group与/dev/ps.cpp#L213-L223——这是 Serenity 安全模型pledge/unveil在用户态工具的典型体现ProcessStatisticsReader::get_all 打开/sys/kernel/processes读取全部内容并解析为 JSON内核侧 SysFSOverallProcesses::try_generate 生成包含processes数组、total_time、total_time_kernel的 JSON 对象每个进程对象携带pid、pgid、sid、uid、gid、ppid、name、executable、tty、creation_time、各类内存量amount_virtual等以及threads子数组含tid、state、cpu、priority等解析器把 JSON 字段逐一映射为Core::ProcessStatistics/Core::ThreadStatistics结构体ProcessStatisticsReader.cpp#L27-L89并用getpwent缓存 UID → 用户名映射ProcessStatisticsReader.cpp#L98-L111从而在-f/uid列中显示用户名而非裸 UIDps完成过滤与排序后按列宽对齐输出数值列右对齐、文本列左对齐ps.cpp#L383-L405列宽取该列所有单元格中最大的字符宽度。完整的数据链路可概括为内核进程链表 └─ SysFS /sys/kernel/processes (JSON 快照) └─ Core::ProcessStatisticsReader::get_all() └─ ps 过滤 / 排序 / 自定义列渲染 └─ 终端输出七、延伸阅读进程内存映射查看pmappmap -x PID可打印指定进程的内存映射进程打开文件查看lsof按 PID / 文件描述符 / 用户 / 进程组筛选用户态解析入口Userland/Utilities/ps.cpp进程统计读取库Userland/Libraries/LibCore/ProcessStatisticsReader.cpp 与 ProcessStatisticsReader.h内核 SysFS 进程节点Kernel/FileSystem/SysFS/Subsystems/Kernel/Processes.cpp。【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价