我试图确定启动进程后是否创建了文件。我正在使用 command 获取进程开始时间ps -f -p PID -o lstart=
。这给了我一个Fri May 5 09:15:35 2017
没有任何时区信息的结果。
另一方面,文件系统为我提供带有时区的日期。当我比较日期时,我得到错误的结果。例子:
- 进程开始:
2017-05-05 10:26:57 +0000 UTC
- 文件修改:
2017-05-05 10:26:57.679508679 +0200 CEST
是否可以使用不同的格式获取进程开始时间,例如 unix 日期? (有毫秒也会有帮助)
上下文:我正在ps
从 go 应用程序运行命令并解析结果。
答案1
文件系统不会为您提供带有时区的时间,它是您用来以人类友好的格式显示该时间的任何命令,如果它选择以本地时间显示时间(由 ,/etc/localtime
或$TZ
指定),则可能会为您提供时区其他)。
通常,Unix 上的时间戳以与时区无关的方式表示。 unix 纪元时间是自历史上的精确事件(1970-01-01 00:00:00 UTC,明确的时间)。仅当以日历格式向人们显示日期时,时区才会出现。
ps -o lstart= -p "$pid"
date -r /some/file
两者都为您提供当地时间。date
可能会输出时区偏移量或不输出,具体取决于区域设置。如果您想要 UTC 时间,请在以下位置运行它们TZ=UTC0
:
TZ=UTC0 ps -o lstart= -p "$pid"
TZ-UTC0 date -r /some/file # or use date -u
GNUdate
能够解析 报告的日期ps
,因此您可以将其转换为任何格式,例如 unix 纪元时间:
(export TZ=UTC0
date -d "$(ps -o lstart -p "$pid") +%s
date -r /some/file +%s)
(以上使用 UTC 时间。它也适用于您环境中的任何本地时间,除了一年中的一个小时,其中没有 TZ 指示的时间输出不明确(在实施 DST 的区域中)。
在任何情况下,进程的启动时间不必是(并且永远不会完全是)进程执行当前正在运行的命令的时间。例如:
$ TZ=UTC0 strace -qtt -e execve sh -c 'sleep 3; exec env ps -o lstart= -p "$$"'
10:27:24.877397 execve("/bin/sh", ["sh", "-c", "sleep 3; exec env ps -o lstart= "...], [/* 28 vars */]) = 0
10:27:27.882553 execve("/usr/bin/env", ["env", "ps", "-o", "lstart=", "-p", "9397"], [/* 28 vars */]) = 0
10:27:27.885272 execve("/bin/ps", ["ps", "-o", "lstart=", "-p", "9397"], [/* 28 vars */]) = 0
Fri May 5 10:27:24 2017
9397 进程在其生命周期中运行 4 个命令:(在那里strace
分叉)sh
、、、、env
。ps
报告的时间ps
对应于它被 fork 的时间strace
,而不是它执行的时间ps
。
如果你想获得亚秒级精度(高达1/$(getconf CLK_TCK)
),使用zsh
,你可以这样做:
zmodload zsh/datetime
tick=$(getconf CLK_TCK)
(echo $((EPOCHREALTIME + (${${=$(</proc/self/stat)##*)}[20]}. -
${${=$(</proc/$pid/stat)##*)}[20]})/tick)))
也就是说,我们获取 $pid 和新创建的子 shell 的开始时间(这是现代版本 Linux 中以 CLK_TCK 表示的字符最后一次出现后的第 20 个字段)
)/proc/pid/stat
,将差值除以CLK_TCK
并添加到当前时间。