I'd like to sort this output by lstart (start of process):

ps -eo lstart,pid,cmd 

Is there a way to output lstart in ISO format like YYYY-MM-DD HH:MM:SS?

But sorting alone does not solve it. I really would like to have ISO date format.

  • Why does lstart have such a wierd format. Its close to RFC 2822 but with year on the end. – vaughan Aug 5 '19 at 23:34

Is there a way to output lstart in ISO format like YYYY-MM-DD HH:MM:SS?

With awk + date cooperation:

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 }'

Alternative approach using ps etimes keyword(elapsed time since the process was started, in seconds):

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 - difference between the current timestamp and elapsed time, will give the timestamp value of the process
| improve this answer | |
  • 2
    Is there no easier way? – guettli Nov 1 '17 at 10:33
  • 3
    If you use ps format etimes instead of lstart you get the elapsed time in seconds which is a bit easier to pass into date -d -999seconds. – meuh Nov 1 '17 at 10:40
  • @meuh, yes, that would be a bit shorter, I've made an update – RomanPerekhrest Nov 1 '17 at 11:29
  • @guettli, can't call it easier, but you got a bit shorter way – RomanPerekhrest Nov 1 '17 at 11:30

You can sort with:

ps -eo lstart,pid,cmd --sort=start_time
| improve this answer | |
  • Thank you, I extended my question. I want iso date format, too. – guettli Nov 1 '17 at 9:14

Note that lstart is not one of the standard Unix ps columns.

Not all systems have one, and the output varies between implementations and potentially between locales.

For instance, on FreeBSD or with the ps from procps-ng (as typically found on non-embedded Linux-based systems) and the C locale, you'll get:

Wed Nov  1 12:36:15 2017

On macOS:

Wed  1 Nov 12:36:15 2017

Also, since, it doesn't give you the GMT offset, the output is ambiguous in timezones that implement DST (where there's one hour during the year where the same dates occur twice) and do not always sort chronologically.

Here, you could force the times to be UTC and use perl's Date::Manip module to parse the date in a way that understands different natural formats:

(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' |

Or with ksh93 which also recognises those date formats:

(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"

(beware it strips trailing blanks from each line)

Or with zsh and 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=)

Or with bash (or zsh) on Linux only and with GNU date:

(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=)"

Also beware that the process start time is not necessarily the same as the last time that process executed a command as processes can an generally do run more than one command in their lifetime (those that don't are generally those that never execute a command). In other words, it doesn't necessarily correspond to the time the command (args field, the standard equivalent of cmd) was started.

$ 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

See how sleep 123 is seen as having been started at the same time as sleep 234 even though it was started 4 seconds later. That's because that 9388 process was initially running sh (and waiting 4 seconds for sleep 4) before it executed sleep 123 (and before that, it was running zsh code as it was forked by my interactive shell, so at different points in time, for that process, you would have seen in the ps output: zsh, then sh, then sleep).

| improve this answer | |
  • 1
    Thank you for your answer. Now I have more questions than before. I thought there is an easy and simple solution. – guettli Nov 2 '17 at 13:56

Here's an implementation with higher performance (does not need to execute a new process per line):

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

and this allows pretty easily to change column ordering, too. For example pid first and start time as second column:

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.