output ps dengan format iso date?

9

Saya ingin menyortir output ini dengan lstart(mulai dari proses):

ps -eo lstart,pid,cmd 

Apakah ada cara untuk menghasilkan lstart dalam format ISO seperti YYYY-MM-DD HH: MM: SS?

Tetapi menyortir sendiri tidak menyelesaikannya. Saya benar-benar ingin memiliki format tanggal ISO.

guettli
sumber
Mengapa lstartmemiliki format yang aneh. Itu dekat dengan RFC 2822 tetapi dengan tahun pada akhirnya.
vaughan

Jawaban:

10

Apakah ada cara untuk menghasilkan lstartdalam format ISO seperti YYYY-MM-DD HH:MM:SS?

Dengan awk+ datekerja sama:

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

Pendekatan alternatif menggunakan kata kunci ps etimes (waktu yang berlalu sejak proses dimulai, dalam detik):

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- perbedaan antara cap waktu saat ini dan elapsedwaktu, akan memberikan nilai cap waktu proses
RomanPerekhrest
sumber
2
Apakah tidak ada cara yang lebih mudah?
guettli
3
Jika Anda menggunakan format ps etimesalih-alih lstartAnda mendapatkan waktu yang berlalu dalam detik yang sedikit lebih mudah untuk dilewatkan date -d -999seconds.
meuh
@meuh, ya, itu akan sedikit lebih pendek, saya telah membuat pembaruan
RomanPerekhrest
@guettli, tidak bisa menyebutnya lebih mudah, tetapi Anda punya cara yang lebih pendek
RomanPerekhrest
4

Anda dapat mengurutkan dengan:

ps -eo lstart,pid,cmd --sort=start_time
Ipor Sircer
sumber
Terima kasih, saya memperpanjang pertanyaan saya. Saya ingin format tanggal iso juga.
guettli
2

Perhatikan bahwa lstartitu bukan salah satu dari pskolom Unix standar .

Tidak semua sistem memiliki satu, dan output bervariasi antara implementasi dan berpotensi antar lokal.

Misalnya, di FreeBSD atau dengan psdari procps-ng(seperti yang biasanya ditemukan pada sistem berbasis Linux yang tidak tertanam) dan Clokal, Anda akan mendapatkan:

Wed Nov  1 12:36:15 2017

Di MacOS:

Wed  1 Nov 12:36:15 2017

Juga, karena tidak memberi Anda offset GMT, outputnya ambigu dalam zona waktu yang menerapkan DST (di mana ada satu jam selama tahun di mana tanggal yang sama terjadi dua kali) dan tidak selalu menyortir secara kronologis.

Di sini, Anda bisa memaksa kali menjadi UTC dan menggunakan perl's Date::Manipmodul untuk mengurai tanggal dengan cara yang mengerti format alam yang berbeda:

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

Atau ksh93yang juga mengenali format tanggal tersebut:

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

(hati-hati, strip kosong kosong dari setiap baris)

Atau dengan zshdan 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=)
)

Atau dengan bash(atau zsh) hanya di Linux dan dengan 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=)"
)

Berhati-hatilah juga bahwa waktu mulai proses tidak harus sama dengan waktu terakhir proses mengeksekusi suatu perintah karena proses secara umum dapat menjalankan lebih dari satu perintah dalam masa hidup mereka (yang biasanya bukan yang tidak pernah menjalankan perintah) . Dengan kata lain, itu tidak selalu sesuai dengan waktu perintah ( argsbidang, standar yang setara dengan cmd) dimulai.

$ 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

Lihat bagaimana sleep 123ini dilihat sebagai telah dimulai pada saat yang sama sleep 234meskipun itu dimulai 4 detik kemudian. Itu karena proses 9388 itu awalnya berjalan sh(dan menunggu 4 detik sleep 4) sebelum dieksekusi sleep 123(dan sebelum itu, itu menjalankan zshkode seperti yang bercabang oleh shell interaktif saya, jadi pada titik waktu yang berbeda, untuk proses itu, Anda harus memiliki terlihat di psoutput:, zshlalu sh, lalu sleep).

Stéphane Chazelas
sumber
1
Terima kasih atas jawaban Anda. Sekarang saya punya lebih banyak pertanyaan daripada sebelumnya. Saya pikir ada solusi yang mudah dan sederhana.
guettli
1

Berikut ini adalah implementasi dengan kinerja yang lebih tinggi (tidak perlu menjalankan proses baru per baris):

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

dan ini memungkinkan cukup mudah untuk mengubah pemesanan kolom juga. Misalnya pidpertama dan waktu mulai sebagai kolom kedua:

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
sumber