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.
Is there a way to output
lstart
in ISO format likeYYYY-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 processetimes
instead of lstart
you get the elapsed time in seconds which is a bit easier to pass into date -d -999seconds
.
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
.
Commented
Aug 23, 2021 at 3:17
You can sort with:
ps -eo lstart,pid,cmd --sort=start_time
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' |
sort
)
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"
done
)
(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
).
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).
The other answers seem outdated. Just pass the option --date-format '%Y-%m-%dT%H:%M:%S'
.
This is available in the latest versions of procps-ng
(Linux's standard).
lstart
month name to be locale-aware by default, so caution is needed! gitlab.com/procps-ng/procps/-/commit/…
lstart
have such a wierd format. Its close to RFC 2822 but with year on the end.