ps Ausgabe mit ISO-Datumsformat?

9

Ich möchte diese Ausgabe nach lstart(Beginn des Prozesses) sortieren :

ps -eo lstart,pid,cmd 

Gibt es eine Möglichkeit, lstart im ISO-Format wie JJJJ-MM-TT HH: MM: SS auszugeben?

Aber das Sortieren allein löst es nicht. Ich hätte wirklich gerne ein ISO-Datumsformat.

guettli
quelle
Warum hat lstartso ein komisches Format. Es liegt in der Nähe von RFC 2822, aber mit dem Jahr am Ende.
Vaughan

Antworten:

10

Gibt es eine Möglichkeit, wie lstartim ISO-Format auszugeben YYYY-MM-DD HH:MM:SS?

Mit awk+ dateKooperation:

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

Alternativer Ansatz mit dem Schlüsselwort ps etimes (verstrichene Zeit seit dem Start des Prozesses in Sekunden):

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- Die Differenz zwischen dem aktuellen Zeitstempel und der elapsedZeit gibt den Zeitstempelwert des Prozesses an
RomanPerekhrest
quelle
2
Gibt es keinen einfacheren Weg?
Guettli
3
Wenn Sie etimesstattdessen das ps-Format verwenden, erhalten lstartSie die verstrichene Zeit in Sekunden, die etwas einfacher zu übermitteln ist date -d -999seconds.
Meuh
@meuh, ja, das wäre etwas kürzer, ich habe ein Update gemacht
RomanPerekhrest
@guettli, kann es nicht einfacher nennen, aber Sie haben einen etwas kürzeren Weg
RomanPerekhrest
4

Sie können sortieren mit:

ps -eo lstart,pid,cmd --sort=start_time
Ipor Sircer
quelle
Danke, ich habe meine Frage erweitert. Ich möchte auch ein ISO-Datumsformat.
Guettli
2

Beachten Sie, dass dies lstartkeine der Standard-Unix- psSpalten ist.

Nicht alle Systeme verfügen über eines, und die Ausgabe variiert zwischen Implementierungen und möglicherweise zwischen Gebietsschemas.

Unter FreeBSD oder mit dem psfrom procps-ng(wie es normalerweise bei nicht eingebetteten Linux-basierten Systemen der CFall ist) und dem Gebietsschema erhalten Sie Folgendes:

Wed Nov  1 12:36:15 2017

Unter macOS:

Wed  1 Nov 12:36:15 2017

Da der GMT-Offset nicht angezeigt wird, ist die Ausgabe in Zeitzonen, in denen die Sommerzeit implementiert ist (in denen es eine Stunde im Jahr gibt, in der dieselben Daten zweimal vorkommen), nicht eindeutig und nicht immer chronologisch sortiert.

Hier können Sie die UTC-Zeiten erzwingen und mithilfe perldes Date::ManipModuls das Datum so analysieren, dass verschiedene natürliche Formate verstanden werden:

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

Oder mit ksh93denen auch diese Datumsformate erkannt werden:

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

(Vorsicht, es werden nachgestellte Leerzeichen von jeder Zeile entfernt)

Oder mit zshund 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=)
)

Oder nur mit bash(oder zsh) unter Linux und mit 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=)"
)

Beachten Sie auch, dass die Prozessstartzeit nicht unbedingt mit der letzten Zeit übereinstimmt, zu der der Prozess einen Befehl ausgeführt hat, da Prozesse im Allgemeinen mehr als einen Befehl in ihrem Leben ausführen können (diejenigen, die dies nicht tun, sind im Allgemeinen diejenigen, die niemals einen Befehl ausführen). . Mit anderen Worten, es entspricht nicht unbedingt der Zeit, zu der der Befehl ( argsFeld, das Standardäquivalent von cmd) gestartet wurde.

$ 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

Sehen Sie, wie sleep 123es als gleichzeitig gestartet angesehen wird sleep 234, obwohl es 4 Sekunden später gestartet wurde. Dies liegt daran, dass dieser 9388-Prozess ursprünglich ausgeführt wurde sh(und 4 Sekunden darauf wartete sleep 4), bevor er ausgeführt wurde sleep 123(und zuvor zshCode ausgeführt wurde, wie er von meiner interaktiven Shell gespalten wurde , sodass Sie ihn zu unterschiedlichen Zeitpunkten für diesen Prozess hätten in der psAusgabe gesehen: zshdann sh, dann sleep).

Stéphane Chazelas
quelle
1
Vielen Dank für Ihre Antwort. Jetzt habe ich mehr Fragen als zuvor. Ich dachte, es gibt eine einfache Lösung.
Guettli
1

Hier ist eine Implementierung mit höherer Leistung (es muss kein neuer Prozess pro Zeile ausgeführt werden):

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

und dies ermöglicht es auch ziemlich einfach, die Spaltenreihenfolge zu ändern. Zum Beispiel piderste und Startzeit als zweite Spalte:

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