sortie ps avec format de date iso?

9

Je voudrais trier cette sortie par lstart(début du processus):

ps -eo lstart,pid,cmd 

Existe-t-il un moyen de sortir lstart au format ISO comme AAAA-MM-JJ HH: MM: SS?

Mais le tri seul ne le résout pas. J'aimerais vraiment avoir le format de date ISO.

guettli
la source
Pourquoi lstartun tel format bizarre. C'est proche de RFC 2822 mais avec l'année à la fin.
vaughan

Réponses:

10

Existe-t-il un moyen de sortie lstartau format ISO comme YYYY-MM-DD HH:MM:SS?

Avec awk+ datecoopération:

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

Approche alternative à l'aide du mot clé ps etimes (temps écoulé depuis le démarrage du processus, en secondes):

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- différence entre l'horodatage actuel et l' elapsedheure, donnera la valeur d' horodatage du processus
RomanPerekhrest
la source
2
N'y a-t-il pas de moyen plus simple?
guettli
3
Si vous utilisez le format ps etimesau lieu de lstartvous obtenez le temps écoulé en secondes, ce qui est un peu plus facile à passer date -d -999seconds.
meuh
@meuh, oui, ce serait un peu plus court, j'ai fait une mise à jour
RomanPerekhrest
@guettli, ne peut pas l'appeler plus facilement, mais vous avez un peu plus court
RomanPerekhrest
4

Vous pouvez trier avec:

ps -eo lstart,pid,cmd --sort=start_time
Ipor Sircer
la source
Merci, j'ai étendu ma question. Je veux aussi le format de date iso.
guettli
2

Notez que ce lstartn'est pas l'une des pscolonnes Unix standard .

Tous les systèmes n'en ont pas et la sortie varie entre les implémentations et potentiellement entre les paramètres régionaux.

Par exemple, sur FreeBSD ou avec le psfrom procps-ng(comme on le trouve généralement sur les systèmes Linux non intégrés) et les Cparamètres régionaux, vous obtiendrez:

Wed Nov  1 12:36:15 2017

Sur macOS:

Wed  1 Nov 12:36:15 2017

De plus, comme il ne vous donne pas le décalage GMT, la sortie est ambiguë dans les fuseaux horaires qui implémentent l'heure d'été (où il y a une heure dans l'année où les mêmes dates se produisent deux fois) et ne trient pas toujours chronologiquement.

Ici, vous pouvez forcer les heures à être UTC et utiliser perlle Date::Manipmodule de pour analyser la date d'une manière qui comprend différents formats naturels:

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

Ou avec ksh93lequel reconnaît également ces formats de date:

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

(attention, il supprime les blancs de fin de chaque ligne)

Ou avec zshet 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=)
)

Ou avec bash(ou zsh) sur Linux uniquement et avec 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=)"
)

Sachez également que l'heure de début du processus n'est pas nécessairement la même que la dernière fois que le processus a exécuté une commande car les processus peuvent généralement exécuter plus d'une commande au cours de leur vie (ceux qui ne le sont généralement pas ceux qui n'exécutent jamais une commande) . En d'autres termes, cela ne correspond pas nécessairement au moment où la commande ( argschamp, l'équivalent standard de cmd) a été lancée.

$ 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

Voyez comment sleep 123est considéré comme démarré en même temps que sleep 234même s'il a été démarré 4 secondes plus tard. C'est parce que ce processus 9388 était initialement en cours d'exécution sh(et attendait 4 secondes sleep 4) avant d'être exécuté sleep 123(et avant cela, il exécutait du zshcode tel qu'il était bifurqué par mon shell interactif, donc à différents moments, pour ce processus, vous auriez vu dans la pssortie:, zshalors sh, alors sleep).

Stéphane Chazelas
la source
1
Merci pour votre réponse. Maintenant, j'ai plus de questions qu'auparavant. Je pensais qu'il y avait une solution facile et simple.
guettli
1

Voici une implémentation avec des performances plus élevées (n'a pas besoin d'exécuter un nouveau processus par ligne):

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

et cela permet aussi de changer assez facilement l'ordre des colonnes. Par exemple, la pidpremière et l'heure de début dans la deuxième colonne:

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
la source