Bir komuttan her çıktı satırına zaman damgası hazırlama


Yanıtlar:


274

moreutilsts bunu oldukça iyi yapanları içerir :

command | ts '[%Y-%m-%d %H:%M:%S]'

Aynı zamanda bir döngü ihtiyacını da ortadan kaldırır, her çıktı satırının üzerine bir zaman damgası konur.

$ echo -e "foo\nbar\nbaz" | ts '[%Y-%m-%d %H:%M:%S]'
[2011-12-13 22:07:03] foo
[2011-12-13 22:07:03] bar
[2011-12-13 22:07:03] baz

Sunucunun ne zaman geri geldiğini bilmek ister misiniz? Sadece koş ping | ts, problem çözüldü: D.


8
Bunu nasıl bilemedim?!?!?! Bu kuyruk tamamlar - inanılmaz! tail -f /tmp/script.results.txt | ts
Bruno Bronosky

Peki ya cygwin? Benzer bir şey var mı? Görünüşe göre Joey'nin daha fazlası orada.
CrazyPenguin

3
ts komutum yoksa ne kullanmalıyım?
ekassis

1
İşe yaramıyor ise örneğin stdout'a Stderr yönlendirme deneyinssh -v 127.0.0.1 2>&1 | ts
jchook

3
Parametrenin -sişaretinin faydalı olduğunu düşünüyorum . Bu komutun çalışma zamanını görüntüler. Ben şahsen ikisini de kullanarak ister tsve ts -saynı zamanda. Böyle bir şey görünüyor: command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'. Bu, günlük satırlarını şu şekilde [2018-12-04 08:31:00 (00:26:28.267126)] Hai <3
hazırlar

100

Öncelikle, bu zaman damgalarının gerçekte bir olayı temsil etmesini bekliyorsanız, birçok programın satır tamponlama işlemi gerçekleştirdiğinden (bazıları diğerlerinden daha agresif bir şekilde) gerçekleştiğinden, bunun orijinal satırın olacağı zamana yakın olduğunu düşünmenin önemli olduğunu unutmayın. gerçekleşen bir eylemin zaman damgası yerine basılmıştır.

Ayrıca, komutunuzun zaten bunu yapmaya adanmış yerleşik bir özelliğe sahip olmadığını kontrol etmek isteyebilirsiniz. Örnek olarak, ping -Dbazı pingsürümlerde var ve Unix döneminden beri her satırdan önceki zamanı yazdırıyor. Ancak emriniz kendi yöntemini içermiyorsa, diğerlerinin yanı sıra kullanılabilecek birkaç yöntem ve araç vardır:

POSIX kabuğu

Birçok mermi dizelerini dahili olarak cstrings olarak sakladığından, giriş boş karakter ( \0) içeriyorsa , satırın zamanından önce bitmesine neden olabileceğini unutmayın.

command | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done

GNU awk

command | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }'

Perl

command | perl -pe 'use POSIX strftime; print strftime "[%Y-%m-%d %H:%M:%S] ", localtime'

piton

command | python -c 'import sys,time;sys.stdout.write("".join(( " ".join((time.strftime("[%Y-%m-%d %H:%M:%S]", time.localtime()), line)) for line in sys.stdin )))'

Yakut

command | ruby -pe 'print Time.now.strftime("[%Y-%m-%d %H:%M:%S] ")'

3
Buradaki bir problem, birçok programın stdout'u terminal yerine bir boru olduğunda çıktı tamponlamayı daha da açmasıdır.
cjm

3
@cjm - Doğru. Bazı çıkış arabelleği, kullanma kullanılarak hafifletilebilir stdbuf -o 0, ancak program, çıkış arabelleğini el ile kullanıyorsa , yardımcı olmaz (çıkış arabelleğinin boyutunu devre dışı bırakmak / azaltmak için bir seçenek olmadığı sürece).
Chris Down

2
Python için satır arabelleğini devre dışı bırakabilirsinizpython -u
ibizaman

@Bwmat No., ... for x in sys.stdinönce hepsini belleğe tamponlamadan çizgiler üzerinde yinelenir.
Chris Down,

Bunu yapın ve arabelleğe alın ... ... 1 1 1 1 1 için; 1 uyu; Eko; bitti | python -c 'import sys, time; sys.stdout.write ("". join (("" .join ((time.strftime ("[% Y -% m -% d% H:% M:% S]) ", time.gmtime ()), line)) sys.stdin'deki satır için))) '
ChuckCottrill

41

Satır satır delta ölçümü için gnomon'u deneyin .

Zaman damgası bilgilerini başka bir komutun standart çıktısına hazırlamak için, moreutils ts gibi bir komut satırı yardımcı programıdır. Neyin uzun sürdüğünü gösteren tarihsel bir kayıt istediğiniz uzun süren işlemler için kullanışlıdır.

Herhangi bir şeyi gnomon'a pipetlemek, her satıra bir zaman damgası hazırlar ve bu satırın tampondaki son satır olduğunu gösterir - yani, sonraki satırın ne kadar sürdüğünü gösterir. Varsayılan olarak, gnomon her satır arasında geçen saniye gösterecektir, ancak bu yapılandırılabilir.

gnomon demosu


tsCanlı işlemleri kullanırken harika bir alternatif gibi görünüyor . tsİnteraktif olmayan işlemler için daha uygun olsa da.
BrainStone

7

Ryan'ın görevi ilginç bir fikir veriyor, ancak birçok konuda başarısız oluyor. Test ederken , saniye cinsinden farklılık tail -f /var/log/syslog | xargs -L 1 echo $(date +'[%Y-%m-%d %H:%M:%S]') $1 olsa bile zaman damgasının aynı kaldığını fark ettim stdout. Bu çıktıyı göz önünde bulundurun:

[2016-07-14 01:44:25] Jul 14 01:44:32 eagle dhclient[16091]: DHCPREQUEST of 192.168.0.78 on wlan7 to 255.255.255.255 port 67 (xid=0x411b8c21)
[2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: Joining mDNS multicast group on interface wlan7.IPv6 with address fe80::d253:49ff:fe3d:53fd.
[2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: New relevant interface wlan7.IPv6 for mDNS.

Önerilen çözümüm benzer, ancak uygun zaman damgası sağlıyor ve kullanımdan printfziyade biraz daha taşınabilirecho

| xargs -L 1 bash  -c 'printf "[%s] %s\n" "$(date +%Y-%m-%d\ %H:%M:%S )" "$*" ' bash

Neden bash -c '...' bash? Çünkü -cseçenek nedeniyle , ilk argüman $0çıktıya atanır ve çıkmaz. 'Nin doğru açıklaması için kabuğunuzun el kitabına bakın.-c

İle bu çözümü test tail -f /var/log/syslogayırmadan ve benim wifi yeniden bağlanmadan ve (muhtemelen tahmin edebileceği gibi), göstermiştir uygun zaman damgası her ikisi tarafından sağlanan dateve syslogmesajlar

Bash, herhangi bir burur benzeri kabuk ile değiştirilebilir, ya kshda dashen azından -cseçeneğe sahip olanlarla yapılabilir .

Potansiyel sorunlar:

Çözüm xargs, POSIX uyumlu sistemlerde bulunmasını gerektiriyor , bu nedenle çoğu Unix benzeri sistem ele alınmalı. Açıkçası, sisteminiz POSIX uyumlu değilse veya yoksaGNU findutils


5

Yukarıda yorum yapmayı tercih ederdim, ama itibarlı olarak yapamam. Her neyse, yukarıdaki Perl örneği şu şekilde tamponlanabilir:

command | perl -pe 'use POSIX strftime; 
                    $|=1; 
                    select((select(STDERR), $| = 1)[0]);
                    print strftime "[%Y-%m-%d %H:%M:%S] ", localtime'

İlk '$ |' tamponları STDOUT. İkincisi, stderr'yi geçerli varsayılan çıkış kanalı olarak ayarlar ve ayırır. Select $ | 'in orjinal ayarını döndürdüğünden, seçimin seçimin içinde kaydırılmasıyla $ | varsayılan olarak, STDOUT.

Ve evet, macunu olduğu gibi kesebilirsiniz. Ben okunaklı olması için çok dizilmiş.

Ve gerçekten hassas olmak istiyorsanız (ve Time :: Hires yüklü):

command | perl -pe 'use POSIX strftime; use Time::HiRes gettimeofday;
                    $|=1; 
                    select((select(STDERR), $| = 1)[0]);
                    ($s,$ms)=gettimeofday();
                    $ms=substr(q(000000) . $ms,-6);
                    print strftime "[%Y-%m-%d %H:%M:%S.$ms]", localtime($s)'

1
Standart olmayan herhangi bir paket kurmak zorunda kalmadan bir cazibe gibi çalışır.
Jay Taylor

2

Cevapların çoğu kullanmayı önerir date, ancak yeterince yavaş. Eğer bash versiyonunuz 4.2.0'dan büyükse printfbunun yerine kullanmak daha iyidir , bir bash yerleşimidir. Eski bash sürümlerini desteklemeniz gerekiyorsa, oluşturabileceğiniz logişlev bash sürümüne bağlıdır:

TIMESTAMP_FORMAT='%Y-%m-%dT%H:%M:%S'
# Bash version in numbers like 4003046, where 4 is major version, 003 is minor, 046 is subminor.
printf -v BV '%d%03d%03d' ${BASH_VERSINFO[0]} ${BASH_VERSINFO[1]} ${BASH_VERSINFO[2]}
if ((BV > 4002000)); then
log() {
    ## Fast (builtin) but sec is min sample for most implementations
    printf "%(${TIMESTAMP_FORMAT})T %5d %s\n" '-1' $$ "$*"  # %b convert escapes, %s print as is
}
else
log() {
    ## Slow (subshell, date) but support nanoseconds and legacy bash versions
    echo "$(date +"${TIMESTAMP_FORMAT}") $$ $*"
}
fi

Hız farklarına bakınız:

user@host:~$time for i in {1..10000}; do printf "%(${TIMESTAMP_FORMAT})T %s\n" '-1' "Some text" >/dev/null; done

real    0m0.410s
user    0m0.272s
sys     0m0.096s
user@host:~$time for i in {1..10000}; do echo "$(date +"${TIMESTAMP_FORMAT}") Some text" >/dev/null; done

real    0m27.377s
user    0m1.404s
sys     0m5.432s

UPD: Bunun yerine $(date +"${TIMESTAMP_FORMAT}")kullanmak daha iyi, $(exec date +"${TIMESTAMP_FORMAT}")hatta $(exec -c date +"${TIMESTAMP_FORMAT}")çok fazla hızlanma yürütme.


0

Bunu dateve ile yapabilirsiniz xargs:

... | xargs -L 1 echo `date +'[%Y-%m-%d %H:%M:%S]'` $1

Açıklama:

xargs -L 1xargs'a, her 1 satırlık girdi için ilerletme komutunu çalıştırmasını söyler ve ilk satırda olduğu gibi geçer. echo `date +'[%Y-%m-%d %H:%M:%S]'` $1Temel olarak tarihi, sonunda girilen argümanla ekolar.


2
Çözüm yakın, ancak uzun sürelerle ayrılmış çıktı söz konusu olduğunda doğru zaman damgası vermiyor. Ayrıca, backticks kullanıyorsunuz ve alıntı yapmadınız $1. Bu iyi bir tarz değil. Değişkenleri daima alıntılayın. Ayrıca, echotaşınabilir olmayan kullanıyorsunuz . Sorun değil, ancak bazı sistemlerde düzgün çalışmayabilir.
Sergiy Kolodyazhnyy

Bunu test ettikten sonra, kesinlikle haklısınız ... dateher çizgiyi yeniden değerlendirmenin bir yolunu biliyor musunuz , yoksa neredeyse ümitsiz mi?
Ryan,
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.