最简单可靠的方案是用 ps -o etime= -p pid 获取进程启动以来的完整秒数(向下取整),数值稳定、无 locale 和跨年影响;需加 = 抑制表头,用 xargs 清理空格;旧系统或容器中可能不支持,需降级处理。

直接用 ps -o etime= -p PID 获取整秒数
这是最简单、最可靠的方案。etime 字段表示进程自启动以来经过的**完整秒数(向下取整)**,包含休眠时间,数值稳定、无歧义。它不依赖 locale,也不受跨年/跨月影响。
-
ps -o etime= -p 1234输出纯数字,末尾带空格;加| xargs可干净提取:ps -o etime= -p 1234 | xargs - 注意
=紧跟在etime后面——这是为了抑制表头,避免脚本解析失败 - 旧版系统(如 CentOS 6)可能不支持
etime,会报错或输出空白;此时需 fallback 到lstart或/proc/PID/stat - 容器内进程若运行在较老 Docker(etime 可能从容器启动起算,而非 exec 时间点
为什么不能用 time 或 TIME+ 字段
time(ps aux 第 10 列)和 top 的 TIME+ 列本质相同:它们是**CPU 占用时间总和,单位是 1/100 秒**,不是存活时长。一个休眠 23 小时的进程,TIME+ 可能只有几秒。
-
ps -o time= -p 1234输出类似00:05:22,实际是 5 分 22 秒 CPU 时间,不是运行时长 -
top中按f加ELAPSED字段虽可显示真实秒数,但该字段仅存在于较新 procps-ng(RHEL 8+/Ubuntu 20.04+),且值与etime一致——不如直接用ps - 别被
STIME或stime迷惑:它们只表示“距系统启动的秒数”,没上下文根本无法换算成真实时间
需要毫秒级精度?走 /proc/PID/stat + CLK_TCK
当 etime 的整秒精度不够(比如压测、调试 fork 行为),就得下探到内核层:/proc/PID/stat 第 22 字段是进程启动时刻的 jiffies 数,结合 getconf CLK_TCK 和 /proc/stat 中的 btime 才能还原精确启动时间戳。
- 执行
getconf CLK_TCK确认滴答频率(绝大多数系统为100) -
awk '{print $22}' /proc/1234/stat得到 jiffies 值;grep btime /proc/stat | awk '{print $2}'得到系统启动 Unix 时间戳 - 计算公式:
启动秒数 = (jiffies / CLK_TCK) + btime;当前时间减去它即得已运行秒数(含小数) - 这条路径精度最高,但命令易出错,建议封装成小脚本;另外,
/proc/PID/stat在容器 PID namespace 中仍有效,比ps更底层可信
别忽略 etime 为负的异常情况
极少数情况下,ps -o etime= -p PID 返回负值(如 -1),说明该进程刚 fork 完尚未 exec,内核还没记录有效启动时间点。
- 此时应跳过该值,或配合
ps -o stat= -p PID检查状态:若含<code>W(无驻留内存)或<code>Z(僵尸),etime就不可信 - 同一进程多次采样出现
etime跳变(如从 1200 突变为 10),大概率是 PID 复用——旧进程已退出,新进程占用了相同 PID - 如果目标进程由 shell 子进程启动(如
bash -c 'sleep 100'),etime从bash启动算起,不是从sleep开始;要测具体命令,得用/usr/bin/time -v或SECONDS变量
etime 是默认首选,但它的“整秒”特性在毫秒敏感场景下就是硬伤;而手动解析 /proc 虽准,却容易在 awk 分隔符、CLK_TCK 假设、浮点运算上翻车。











