¿Salida de ps con formato de fecha iso?

9

Me gustaría ordenar esta salida por lstart(inicio del proceso):

ps -eo lstart,pid,cmd 

¿Hay alguna manera de generar lstart en formato ISO como AAAA-MM-DD HH: MM: SS?

Pero ordenar solo no lo resuelve. Realmente me gustaría tener el formato de fecha ISO.

guettli
fuente
¿Por qué lstarttiene un formato tan extraño? Está cerca de RFC 2822 pero con año al final.
vaughan

Respuestas:

10

¿Hay alguna forma de salida lstarten formato ISO como YYYY-MM-DD HH:MM:SS?

Con awk+ datecooperación:

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

Enfoque alternativo utilizando la palabra clave ps etimes (tiempo transcurrido desde que se inició el proceso, en segundos):

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- diferencia entre la marca de elapsedtiempo actual y la hora, dará el valor de marca de tiempo del proceso
RomanPerekhrest
fuente
2
¿No hay una manera más fácil?
guettli
3
Si usa el formato ps en etimeslugar de lstartobtener el tiempo transcurrido en segundos, que es un poco más fácil de pasar date -d -999seconds.
meuh
@meuh, sí, eso sería un poco más corto, hice una actualización
RomanPerekhrest el
@guettli, no puedo llamarlo más fácil, pero tienes un camino un poco más corto
RomanPerekhrest el
4

Puedes ordenar con:

ps -eo lstart,pid,cmd --sort=start_time
Ipor Sircer
fuente
Gracias, extendí mi pregunta. También quiero el formato de fecha iso.
Guettli
2

Tenga en cuenta que lstartno es una de las pscolumnas estándar de Unix .

No todos los sistemas tienen uno, y la salida varía entre implementaciones y potencialmente entre entornos locales.

Por ejemplo, en FreeBSD o con psfrom procps-ng(como se encuentra típicamente en sistemas basados ​​en Linux no integrados) y la Cconfiguración regional, obtendrá:

Wed Nov  1 12:36:15 2017

En macOS:

Wed  1 Nov 12:36:15 2017

Además, dado que no le da el desplazamiento de GMT, la salida es ambigua en las zonas horarias que implementan DST (donde hay una hora durante el año donde ocurren las mismas fechas dos veces) y no siempre se clasifican cronológicamente.

Aquí, puede forzar que las horas sean UTC y usar perlel Date::Manipmódulo para analizar la fecha de una manera que comprenda los diferentes formatos naturales:

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

O con el ksh93que también reconoce esos formatos de fecha:

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

(tenga cuidado con que elimina los espacios en blanco finales de cada línea)

O con zshy 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=)
)

O con bash(o zsh) solo en Linux y con 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=)"
)

También tenga en cuenta que el tiempo de inicio del proceso no es necesariamente el mismo que la última vez que el proceso ejecutó un comando, ya que los procesos generalmente pueden ejecutar más de un comando en su vida (los que no son generalmente los que nunca ejecutan un comando) . En otras palabras, no necesariamente corresponde a la hora en que se inició el comando ( argscampo, el equivalente estándar de cmd).

$ 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

Vea cómo sleep 123se considera que se inició al mismo tiempo que sleep 234aunque se inició 4 segundos después. Eso se debe a que ese proceso 9388 se estaba ejecutando inicialmente sh(y esperando 4 segundos sleep 4) antes de ejecutarse sleep 123(y antes de eso, se estaba ejecutando el zshcódigo tal como lo bifurcó mi shell interactivo, por lo que en diferentes momentos, para ese proceso, habría visto en la pssalida:, zshentonces sh, entonces sleep).

Stéphane Chazelas
fuente
1
Gracias por su respuesta. Ahora tengo más preguntas que antes. Pensé que hay una solución fácil y simple.
guettli
1

Aquí hay una implementación con mayor rendimiento (no necesita ejecutar un nuevo proceso por línea):

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

y esto también permite cambiar fácilmente el orden de las columnas. Por ejemplo, pidprimero y hora de inicio como segunda columna:

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
fuente