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, 2019 at 23:34

4 Answers 4


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
  • 3
    Is there no easier way?
    – guettli
    Nov 1, 2017 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, 2017 at 10:40
  • @meuh, yes, that would be a bit shorter, I've made an update Nov 1, 2017 at 11:29
  • @guettli, can't call it easier, but you got a bit shorter way Nov 1, 2017 at 11:30
  • And check if your ps has --no-headers or you can adjust the awk to have NR>1 at the front, or else just run with 2>/dev/null.
    – bgStack15
    Aug 23, 2021 at 3:17

You can sort with:

ps -eo lstart,pid,cmd --sort=start_time
  • Thank you, I extended my question. I want iso date format, too.
    – guettli
    Nov 1, 2017 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).

  • 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, 2017 at 13:56

Here's an implementation with higher performance (does not need to execute a new process per line, sorts oldest process as the last):

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, etimes, arg. And to primary sort by start time and secondary by pid, you can do something like:

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

(the etimes must be sorted in reverse because it's actually count of seconds in the past for the process start time, this should match the actual execution order of the processes except if PID counter overflows on the same second for multiple processes).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .