Zaman damgalarını stdin'e eklemek için bir Unix yardımcı programı var mı?


168

Python'da bunun için hızlı bir komut dosyası yazdım, ancak her satırın bazı metinlerle başlayabileceği bir metni (belirli bir durumda, bir zaman damgası) başlatacak bir yardımcı program olup olmadığını merak ediyordum. İdeal olarak, kullanım aşağıdaki gibi bir şey olacaktır:

cat somefile.txt | prepend-timestamp

(Sed'e cevap vermeden önce bunu denedim:

cat somefile.txt | sed "s/^/`date`/"

Ancak bu, sed yürütüldüğünde date komutunu yalnızca bir kez değerlendirir, bu nedenle aynı zaman damgası her satıra yanlış eklenir.)


cat somefile.txt"yanıltıcı" biraz? Bunun "bir kerede" olmasını ve tek bir zaman damgasına sahip olmasını beklerdim. Bu daha iyi bir test programı olmaz (echo a; sleep 1; echo b; sleep 3; echo c; sleep 2)mı?
Ciro Santilli 法轮功 at 病 六四 事件 法轮功

Yanıtlar:


185

Kullanmayı deneyebiliriz awk:

<command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; fflush(); }'

<command>Hat tamponlu çıktı ürettiğinden emin olmanız gerekebilir , yani her satırdan sonra çıktı akışını temizler; zaman damgası awkeklenen satırın sonunun giriş borusunda göründüğü zamandır.

Awk hata gösteriyorsa, gawkbunun yerine deneyin .


31
Benim sistemimde 'awk' nin kendisi arabelleğe alınıyordu. (Bu günlük dosyaları için sorunlu olabilir). Bunu şunu kullanarak çözdüm: awk '{print strftime ("% Y-% m-% dT% H:% M:% S"), $ 0; ) (fflush; } '
user47741

19
strftime () bir GNU awk uzantısı gibi görünüyor, bu nedenle Mac OS kullanıyorsanız awk yerine gawk kullanın.
Joe Shaw

Bash'ın ne kadar güçlü olduğunu beni şaşırtmak bitmiyor. Bu karmaşık görev için bu kadar kolay bir çözüm olacağını düşünmemiştim.
recluze

2
OS X kullanıcıları gawkiçin bunun yerine yüklemeniz ve kullanmanız gerekir awk. MacPorts'unuz varsa:sudo port install gawk
Matt Williamson

5
@teh_senaus olarak bildiğim kadarıyla, awk'ın strftime()milisaniye hassasiyet yok. Ancak datekomutu kullanabilirsiniz . Temel olarak nanosaniyeyi üç karaktere kırpıyorsunuz. Bu şekilde görünecektir: COMMAND | while read -r line; do echo "$(date '+%Y-%m-%d %T.%3N') $line"; done. % H:% M:% S ile% T kısaltmayı yapabileceğinizi unutmayın. Hala bir awksebepten dolayı kullanmak istiyorsanız, aşağıdakileri yapabilirsiniz:COMMAND | awk '{ "date +%Y-%m-%d\\ %T.%3N" | getline timestamp; print timestamp, $0; fflush(); }'
Altı

190

tsdan moreutils girdi her satıra bir zaman damgası prepend olacak sen ver. Bunu strftime kullanarak da biçimlendirebilirsiniz.

$ echo 'foo bar baz' | ts
Mar 21 18:07:28 foo bar baz
$ echo 'blah blah blah' | ts '%F %T'
2012-03-21 18:07:30 blah blah blah
$ 

Yüklemek için:

sudo apt-get install moreutils

2
bad command 2>&1 | tsJan 29 19:58:31 -bash: bad: command not found
stderr'ı

Saat biçimini kullanmak istiyorum 2014 Mar 21 18:07:28. Onu nasıl alırım?
becko

@becko - manuel sayfaya göre , strftimeargüman olarak bir biçim dizesi verin : [.. command ..] | ts '%Y %b %d %T'örneğin.
Toby Speight

2
OS X için brew install moreutils,. UTC çıktısını almak için, ls -l |TZ=UTC ts '%Y-%m-%dT%H:%M:%SZ'
TZ'yi

1
@ Dorian bunun nedeni ruby ​​çıktıyı arabelleğe almasıdır; uyumadan önce tamponu ruby -e "puts 1; STDOUT.flush; sleep 1; puts 2; STDOUT.flush; sleep 2; puts 3" | ts '%F %T'
yıkarsanız

45

bu bağlantı üzerinden veya annotate-outputDebian devscriptspaketinde olduğu gibi ek açıklama ekleyin .

$ echo -e "a\nb\nc" > lines
$ annotate-output cat lines
17:00:47 I: Started cat lines
17:00:47 O: a
17:00:47 O: b
17:00:47 O: c
17:00:47 I: Finished with exitcode 0

1
Bu harika bir çözümdür, ancak borulu çıkış veya alt kabuk çıktısı ile çalışmaz. Yalnızca bağımsız değişken olarak verdiğiniz bir program veya komut dosyasının çıktısını yeniden biçimlendirir.
slm

1
ek açıklama çıktısı iyi çalışır ve kullanımı kolaydır, ancak GERÇEKTEN yavaştır.
Paul Brannan

31

Verilen cevapları mümkün olan en basit olana damıtmak:

unbuffer $COMMAND | ts

Ubuntu'da, wait-dev ve moreutils paketlerinden geliyorlar.

sudo apt-get install expect-dev moreutils

1
Öyle expectdeğil expect-dev, ama ikincisi birincisini çekiyor, bu yüzden çalışıyor. (Ubuntu 14.10, ikilinin bir noktada farklı bir pakete taşınıp taşınmadığını merak ediyorum.)
Marius Gedminas

Ubuntu 14.04 LTS için halaexpect-dev
Willem

2
Geçen süreyi milisaniye hassasiyetle almak istiyorsanız, unbuffer $COMMAND | ts -s %.s( -sgeçen süre ve %.skesirli kısmı olan saniyeler içinde) için kullanın
Greg Witczak

24

Buna ne dersin?

cat somefile.txt | perl -pne 'print scalar(localtime()), " ";'

Canlı zaman damgaları alma isteğinizden yola çıkarak, belki bir günlük dosyasında veya bir şeyde canlı güncelleme yapmak istersiniz? Olabilir

tail -f /path/to/log | perl -pne 'print scalar(localtime()), " ";' > /path/to/log-with-timestamps

4
Görünüşe göre 'gawk' yerine 'mawk' kullanan ve strftime işlevi olmayan ubuntu dağıtımında kullanıcı olarak çalıştığım için bu perl örneği özellikle benim için yararlı oldu. Teşekkürler!
opello

4
+1, varsayılan bir Ubuntu kurulumunda kullanışlıdır. Daha tail -f /path/to/log | perl -pne 'use POSIX qw(strftime); print strftime "%Y-%m-%dT%H:%M:%SZ ", gmtime();'basit versiyonun verdiği wacko yerine ISO8601 / RFC3339 stil tarihini alırdım.
natevw

1
Zaman damgalı günlük çıktısına geldiğinde bakmak istiyorsanız BEGIN { $|++; }, Perl'in her satırla çıktısını temizlemesi için print ifadesinden önce eklemek yararlı olabilir .

2
Perl betiğini daha da kısaltabilirsiniz ls | perl -pne 'print localtime." "'. Skaler dönüşüm dize birleştirme nedeniyle gerçekleşir.
rahul

Neden hem kullanıyorsunuz -pve -nseçenekleri? -nEğer belirtmişseniz gereksiz gibi görünüyor -p.
Davor Cubranic


18

Kieron'un cevabı şimdiye kadarki en iyisi. İlk programın arabelleğe alınması nedeniyle sorun yaşarsanız, arabelleğe alma programını kullanabilirsiniz:

unbuffer <command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; }'

Çoğu linux sisteminde varsayılan olarak kurulur. Kendiniz inşa etmeniz gerekiyorsa, beklemek paketinin bir parçasıdır

http://expect.nist.gov


Unbuffer'ın bazen çağrılan programın geri dönüş sonucunu gizlediğini bulduğumu unutmayın - bu nedenle Jenkins veya dönüş durumuna dayanan diğer şeylerde yararlı değildir
oskarpearson

10

Standart girişten her seferinde bir satır okumak için read (1) komutunu kullanın, ardından tarihle birlikte gelen satırı, tarih (1) kullanarak seçtiğiniz biçimde ayarlayın.

$ cat timestamp
#!/bin/sh
while read line
do
  echo `date` $line
done
$ cat somefile.txt | ./timestamp

2
Her hat için yeni bir süreç çatal gibi biraz ağır, ama işe yarıyor!
Joe Shaw

3

Ben Unixli biri değilim ama bence kullanabilirsiniz

gawk '{print strftime("%d/%m/%y",systime()) $0 }' < somefile.txt

3
#! /bin/sh
unbuffer "$@" | perl -e '
use Time::HiRes (gettimeofday);
while(<>) {
        ($s,$ms) = gettimeofday();
        print $s . "." . $ms . " " . $_;
}'

2

İşte benim awk çözüm (C: \ bin dizininde MKS Tools kurulu bir Windows / XP sisteminden). Her tarih okundukça sistemden zaman damgasını alan her satırın başına mm / gg ss: mm biçiminde geçerli tarih ve saati eklemek için tasarlanmıştır. Elbette, zaman damgasını bir kez almak ve bu zaman damgasını her kayda (hepsi aynı) eklemek için BEGIN desenini kullanabilirsiniz. Bunu, günlük iletisinin oluşturulduğu zamandaki zaman damgası ile stdout için oluşturulmuş bir günlük dosyasını etiketlemek için yaptım.

/"pattern"/ "C\:\\\\bin\\\\date '+%m/%d %R'" | getline timestamp;
print timestamp, $0;

burada "desen", giriş satırında eşleştirilecek bir dize veya normal ifade (tırnak işaretleri olmadan) ve tüm giriş satırlarıyla eşleşmek istiyorsanız isteğe bağlıdır.

Bu Linux / UNIX sistemlerinde de çalışmalı, sadece çizgiden ayrılan C \: \\ bin \\ 'dan kurtulun

             "date '+%m/%d %R'" | getline timestamp;

Bu, elbette, "tarih" komutunun sizi belirli yol bilgileri olmadan standart Linux / UNIX tarih görüntüleme / ayarlama komutuna götürdüğünü varsayar (yani, ortam PATH değişkeniniz doğru yapılandırılmıştır).


OS X'de tarih komutundan önce bir boşluk gerekiyordu. Ne yazık ki her satır için komutu yeniden değerlendiriyor gibi görünmüyor. Diğerlerinin önerdiği gibi, tail -f'ye zaman damgaları eklemeye çalışıyorum.
Mark Bennett

2

Yukarıdaki bazı cevaplar Karıştırma natevw ve Frank Ch. Eigler.

Milisaniye vardır, dateher seferinde harici bir komut çağırmaktan daha iyi performans gösterir ve perl sunucuların çoğunda bulunabilir.

tail -f log | perl -pne '
  use Time::HiRes (gettimeofday);
  use POSIX qw(strftime);
  ($s,$ms) = gettimeofday();
  print strftime "%Y-%m-%dT%H:%M:%S+$ms ", gmtime($s);
  '

Bir döngü içinde floş ve okuma ile alternatif sürüm:

tail -f log | perl -pne '
  use Time::HiRes (gettimeofday); use POSIX qw(strftime);
  $|=1;
  while(<>) {
    ($s,$ms) = gettimeofday();
    print strftime "%Y-%m-%dT%H:%M:%S+$ms $_", gmtime($s);
  }'

1
Yukarıdakilere sahip iki kusur: 1. $ ms hizalanmamış ve sıfır dolgulu. 2. Günlükteki herhangi bir% kod karıştırılır. Böylece baskı hattı yerine şunları kullandım: printf "%s+%06d %s", (strftime "%Y-%m-%dT%H:%M:%S", gmtime($s)), $ms, $_;
Simon Pickup

2
$ cat somefile.txt | sed "s/^/`date`/"

bunu yapabilirsiniz ( gnu / sed ile ):

$ some-command | sed "x;s/.*/date +%T/e;G;s/\n/ /g"

misal:

$ { echo 'line1'; sleep 2; echo 'line2'; } | sed "x;s/.*/date +%T/e;G;s/\n/ /g"
20:24:22 line1
20:24:24 line2

tabii ki, program tarihinin diğer seçeneklerini kullanabilirsiniz . sadece date +%Tihtiyacınız olanla değiştirin .


1

caerwyn'in yanıtı, hat başına yeni süreçleri önleyecek bir alt program olarak çalıştırılabilir:

timestamp(){
   while read line
      do
         echo `date` $line
      done
}

echo testing 123 |timestamp

3
bu date, her hatta ortaya çıkmasını nasıl önler ?
Gyom

@Gyom Her satırda tarihin ortaya çıkmasını engellemez. Kabuğun her çizgide ortaya çıkmasını önler . Ben bash size coud gibi bir şey yapmak ekleyebilirim: timestamp() { while read line; do echo "$(date) $line"; done; }; export -f timestampkaynak bir komut dosyası.
smbear

Tarihin bir alt işlem olarak çağrılması, her satır için yine de yumurtlama anlamına gelir, ancak komut dosyasını ilk başta başlatırsınız.
Peter Hansen

3
dateHer satır için yumurtlama komutunu önlemek için % (datespec) T biçiminde bash printfyerleşik özelliğini kullanmayı deneyin . Bu yüzden benzeyebilir . Shell yapıları doğmaz. Datespec biçimi ie biçimine benzer. Bu, bash gerektirir, o sürümü hangi sürümü desteklediğinden emin değilim . timestamp() { while IFS= read -r line; do printf "%(%F %T)T %s\n" -1 "$line"; done; }strftime(3)dateprintf
Mindaugas Kubilius

1

Feragatname : önerdiğim çözüm Unix yerleşik bir yardımcı program değil.

Birkaç gün önce benzer bir sorunla karşılaştım. Yukarıdaki çözümlerin sözdizimini ve sınırlamalarını beğenmedim, bu yüzden Go'da işi benim için yapmak için hızlı bir şekilde bir program hazırladım.

Aracı buradan kontrol edebilirsiniz: preftime

GitHub projesinin Sürümler bölümünde Linux, MacOS ve Windows için önceden oluşturulmuş yürütülebilir dosyalar vardır .

Araç, eksik çıktı satırlarını işler ve benim bakış açımdan daha kompakt bir sözdizimine sahiptir.

<command> | preftime

İdeal değil, ama birisine yardım etmesi durumunda paylaşırdım.


0

ile yapıyor dateve trve xargsOSX tarih:

alias predate="xargs -I{} sh -c 'date +\"%Y-%m-%d %H:%M:%S\" | tr \"\n\" \" \"; echo \"{}\"'"
<command> | predate

milisaniye istiyorsanız:

alias predate="xargs -I{} sh -c 'date +\"%Y-%m-%d %H:%M:%S.%3N\" | tr \"\n\" \" \"; echo \"{}\"'"

ancak OSX'te, tarihin size% N seçeneğini vermediğini, bu nedenle gdate ( brew install coreutils) yüklemeniz ve sonunda buna ulaşmanız gerektiğini unutmayın:

alias predate="xargs -I{} sh -c 'gdate +\"%Y-%m-%d %H:%M:%S.%3N\" | tr \"\n\" \" \"; echo \"{}\"'"

-1

Eklediğiniz değer her satırda aynıysa, dosyaya emacs ekleyin, ardından:

Ctrl + <space>

dosyanın başlangıcında (o noktayı işaretlemek için), ardından son satırın başına doğru ilerleyin (Alt +> dosyanın sonuna gider ... muhtemelen Shift tuşunu da içerecektir, sonra Ctrl + a bu satırın başına gitmek için) ve:

Ctrl + x r t

Bu, az önce belirttiğiniz dikdörtgene (0 genişliğinde bir dikdörtgen) ekleme komutudur.

2008-8-21 18:45 <orta>

Veya ne eklemek isterseniz ... o metnin 0 genişlik dikdörtgeni içindeki her satıra eklendiğini göreceksiniz.

GÜNCELLEME: Sadece AYNI tarih istemediğini fark ettim, bu yüzden bu işe yaramayacak ... ama bunu biraz daha karmaşık bir özel makro ile emacs'ta yapabilirsin, ama yine de, bu tür dikdörtgen düzenleme hakkında bilmek çok güzel ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.