PS输出ISO日期格式?


9

我想按lstart(过程开始)对输出进行排序:

ps -eo lstart,pid,cmd 

有没有办法以ISO格式输出lstart,例如YYYY-MM-DD HH:MM:SS?

但是单独排序不能解决问题。我真的很想拥有ISO日期格式。


为什么lstart会有这种奇怪的格式。它接近RFC 2822,但最后一年。
vaughan

Answers:


10

有没有办法以lstartISO格式输出YYYY-MM-DD HH:MM:SS

awk+ date合作:

ps -eo lstart,pid,cmd --sort=start_time | awk '{ 
       cmd="date -d\""$1 FS $2 FS $3 FS $4 FS $5"\" +\047%Y-%m-%d %H:%M:%S\047"; 
       cmd | getline d; close(cmd); $1=$2=$3=$4=$5=""; printf "%s\n",d$0 }'

使用ps etimes关键字的替代方法(自启动过程以来经过的时间,以秒为单位):

ps -eo etimes,pid,cmd --sort=etimes | awk '{ 
       cmd="date -d -"$1"seconds +\047%Y-%m-%d %H:%M:%S\047"; 
       cmd | getline d; close(cmd); $1=""; printf "%s\n",d$0 }' 
  • date -d -"$1"seconds-当前时间戳和elapsed时间之间的差,将给出进程的时间戳

2
有没有更简单的方法?
guettli

3
如果您使用ps格式etimes而不是ps ,lstart则需要经过的时间(以秒为单位),这更容易传递给date -d -999seconds
meuh

@meuh,是的,那会短一些,我进行了更新
RomanPerekhrest

@guettli,再简单不过了,但是您的方法

4

您可以通过以下方式进行排序:

ps -eo lstart,pid,cmd --sort=start_time

谢谢,我扩大了我的问题。我也想要iso日期格式。
guettli

2

请注意,这lstart不是标准Unix ps列之一。

并非所有系统都有一个,并且输出在实现之间以及在区域之间可能有所不同。

例如,在FreeBSD上或使用psfrom procps-ng(通常在非嵌入式Linux系统上找到)和C语言环境,您将获得:

Wed Nov  1 12:36:15 2017

在macOS上:

Wed  1 Nov 12:36:15 2017

另外,由于它不会为您提供GMT偏移,因此在实施DST的时区中,输出是不明确的(一年中有一个小时,同一日期出现两次),并且不一定总是按时间顺序排序。

在这里,您可以将时间强制为UTC并使用perlDate::Manip模块以理解不同自然格式的方式解析日期:

(export TZ=UTC0 LC_ALL=C
  ps -A -o lstart= -o pid= -o args= |
    perl -MDate::Manip -lpe '
      s/^(\s*\S+){5}/UnixDate(ParseDate($&), "%Y-%m-%dT%T+00:00")/e' |
    sort
)

ksh93还可识别这些日期格式:

(export TZ=UTC0 LC_ALL=C
  unset -v IFS
  ps -A -o lstart= -o pid= -o args= |
    while read -r a b c d e rest; do
      printf '%(%FT%T+00:00)T %s\n' "$a $b $c $d $e" "$rest"
    done
)

(请注意,它会删除每行的尾随空白)

或with zsh和GNU date

(export LC_ALL=C TZ=UTC0
  (){
    paste -d '\0' <(cut -c1-24 < $1 | date -f- --iso-8601=s) \
                  <(cut -c25-  < $1) | sort
  } =(ps -A -o lstart= -o pid= -o args=)
)

或仅在(Linux上)和GNU上使用bash(或zshdate

(export LC_ALL=C TZ=UTC0
  {
    paste -d '\0' <(cut -c1-24 | date -f- --iso-8601=s) \
                  <(cut -c25- < /dev/stdin) | sort
  } <<< "$(ps -A -o lstart= -o pid= -o args=)"
)

还要注意,进程的开始时间不一定与上次执行命令的时间相同,因为进程通常在其生命周期中确实可以运行多个命令(那些通常不会执行命令的命令) 。换句话说,它不一定与命令(args,标准等效项cmd)的启动时间相对应。

$ sh -c 'sleep 4; exec sleep 123' & sleep 234 & sleep 5
[1] 9380
[2] 9381(export TZ=UTC0 LC_ALL=C; ps -o lstart,pid,args | perl -MDate::Manip -lpe 's/^(\s*\S+){5}/UnixDate(ParseDate($&), "%Y-%m-%dT%T+00:00")/e')

2017-10-30T17:21:06+00:00  3071 zsh
2017-11-01T15:47:48+00:00  9380 sleep 123
2017-11-01T15:47:48+00:00  9381 sleep 234

即使在4秒钟后sleep 123启动,也可以看到如何同时sleep 234启动。那是因为9388进程最初在执行之前sh(正在等待4秒钟sleep 4)正在运行(在此sleep 123之前,它正在运行zsh由我的交互式shell分叉的代码,因此在该进程的不同时间点,您将拥有在ps输出中看到:zsh,然后是sh,然后是sleep)。


1
谢谢您的回答。现在,我有比以前更多的问题了。我认为有一个简单的解决方案。
guettli

1

这是一个性能更高的实现(不需要每行执行一个新的过程):

ps -eo etimes,pid,args --sort=etimes | awk 'BEGIN{now=systime()} {$1=strftime("%Y-%m-%d %H:%M:%S", now-$1); print $0}'

而且,这也很容易更改列顺序。例如,pid第一列和开始时间为第二列:

ps -eo pid,etimes,args --sort=etimes | awk 'BEGIN{now=systime()} {$2=strftime("%Y-%m-%d %H:%M:%S", now-$2); print $0}'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.