PS вывод с форматом даты ISO?

9

Я хотел бы отсортировать этот вывод по lstart(начало процесса):

ps -eo lstart,pid,cmd 

Есть ли способ вывести lstart в формате ISO, например, ГГГГ-ММ-ДД ЧЧ: ММ: СС?

Но сортировка сама по себе не решает проблему. Я действительно хотел бы иметь формат даты ISO.

guettli
источник
Почему lstartтакой странный формат? Это близко к RFC 2822, но год заканчивается.
Вон

Ответы:

10

Есть ли способ вывода lstartв формате ISO, как YYYY-MM-DD HH:MM:SS?

С awk+ dateсотрудничество:

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

Альтернативный подход с использованием ключевого слова ps etimes (время, прошедшее с момента запуска процесса, в секундах):

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- разница между текущей меткой времени и elapsedвременем, даст значение метки времени процесса
RomanPerekhrest
источник
2
Нет ли более легкого пути?
Геттли
3
Если вы используете формат ps etimesвместо lstartвас, вы получите истекшее время в секундах, в которое будет немного легче перейти date -d -999seconds.
meuh
@ meuh, да, это было бы немного короче, я сделал обновление
RomanPerekhrest
@ guettli, не могу назвать это проще, но вы получили более короткий путь
RomanPerekhrest
4

Вы можете сортировать с:

ps -eo lstart,pid,cmd --sort=start_time
Ипор Сирсер
источник
Спасибо, я расширил свой вопрос. Я тоже хочу формат даты iso.
Геттли
2

Обратите внимание, что lstartэто не один из стандартных psстолбцов Unix .

Не у всех систем есть одна, и выходные данные варьируются между реализациями и, возможно, между локалями.

Например, во FreeBSD или с psfrom procps-ng(как это обычно бывает в не встроенных системах на основе Linux) и в Cлокали вы получите:

Wed Nov  1 12:36:15 2017

На macOS:

Wed  1 Nov 12:36:15 2017

Кроме того, поскольку он не дает смещения по Гринвичу, выходные данные неоднозначны в часовых поясах, которые реализуют летнее время (где в течение года существует один час, когда одни и те же даты встречаются дважды) и не всегда сортируются в хронологическом порядке.

Здесь, вы можете заставить время быть UTC и использовать perl«s Date::Manipмодуль для разбора даты в пути , который понимает различные природные формы:

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

Или с помощью ksh93которого также распознает эти форматы даты:

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

(будьте осторожны, он снимает конечные пробелы с каждой строки)

Или с помощью zshGNU 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=)
)

Или с bash(или zsh) только в Linux и с 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=)"
)

Также имейте в виду, что время запуска процесса не обязательно совпадает с тем, когда процесс выполнял команду в последний раз, поскольку процессы обычно могут выполнять более одной команды за время жизни (обычно это не те команды, которые никогда не выполняют команду) , Другими словами, это не обязательно соответствует времени, когда команда ( argsполе, стандартный эквивалент 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

Посмотрите, как sleep 123видно, что он был запущен в то же время, sleep 234хотя и был запущен через 4 секунды. Это потому, что процесс 9388 изначально выполнялся sh(и ждал 4 секунды sleep 4) перед тем, как он выполнялся sleep 123(и до этого он выполнял zshкод, который был разветвлен моей интерактивной оболочкой, так что в разные моменты времени для этого процесса вы могли бы иметь видно в psвыводе: zshто sh, то sleep).

Стефан Шазелас
источник
1
Спасибо за ваш ответ. Теперь у меня больше вопросов, чем раньше. Я думал, что есть легкое и простое решение.
Геттли
1

Вот реализация с более высокой производительностью (не нужно выполнять новый процесс на строку):

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

и это позволяет довольно легко изменить порядок столбцов. Например, pidпервое и начальное время как второй столбец:

ps -eo pid,etimes,args --sort=etimes | awk 'BEGIN{now=systime()} {$2=strftime("%Y-%m-%d %H:%M:%S", now-$2); print $0}'
Микко Ранталайнен
источник