Bash betiği günlüğüne zaman damgası nasıl eklenir?


94

Sürekli çalışan bir komut dosyasına bir günlük dosyasına çıktıyorum:

script.sh >> /var/log/logfile

Günlüğe eklenen her satırdan önce bir zaman damgası eklemek istiyorum. Sevmek:

Sat Sep 10 21:33:06 UTC 2011 The server has booted up.  Hmmph.

Kullanabileceğim bir jujitsu var mı?


2
Bu görevi görün. serverfault.com/questions/80749/… . Birkaç cevap burada geçerlidir.
Zoredache

Bir awk / gawk çözümü için bakınız: stackoverflow.com/questions/21564/…
Kullanıcı

: İşte bash için giriş kapsamlı bir uygulamasıdır github.com/codeforester/base/blob/master/lib/stdlib.sh
codeforester

Yanıtlar:


88

Komut dosyasının çıktısını geçerli tarih ve saate ekleyen bir döngüden geçirebilirsiniz:

./script.sh | while IFS= read -r line; do printf '%s %s\n' "$(date)" "$line"; done >>/var/log/logfile

Bunu çok kullanacaksanız, döngü işlemek için bir bash işlevi yapmak kolaydır:

adddate() {
    while IFS= read -r line; do
        printf '%s %s\n' "$(date)" "$line";
    done
}

./thisscript.sh | adddate >>/var/log/logfile
./thatscript.sh | adddate >>/var/log/logfile
./theotherscript.sh | adddate >>/var/log/logfile

3
@ Nils readbaşlangıçta ve çizginin boşluklarını kesmesini engellemek için bir numaradır . IFS'yi (bash'ın İç Alan Ayırıcısı, temel olarak beyaz boşluk karakterlerinin bir listesi) readkomut için boşaltır .
Gordon Davisson 15:11

2
... ve -r, "\" çıkış karakterini yoksayar. Bu gerçekten her durumda işe yaramalı - büyük komut dosyası.
Nils

7
@ Yok, tamamen kurşun geçirmez değildir, çünkü echokaçış dizilerinin bazı uygulamaları yorumlanır. Eğer değilse , gerçekten değil (tarihi ekleyerek hariç) içerikle uğraşmak istiyorum, yerini echoile komutuprintf "%s %s\n" "$(date)" "$line"
Gordon Davisson

4
ISO-8601 uyumlu bir tarih / zaman damgası ile ilgileniyor olabilirsiniz : date -u +"%Y-%m-%dT%H:%M:%SZ"ya da belki daha hoş date +"%Y-%m-%d %T".
Pablo A,

1
Bu betiğin beklendiği gibi çalışmasına rağmen date, her bir günlük satırı için makinenize ve günlüklerin miktarına bağlı olarak büyük bir dezavantaj oluşturabilecek yeni bir işlem (yürütme ) başlatır . tsVarsa kullanmanızı öneririm , cevabını @willem
Michael Schaefers

56

tsUbuntu moreutilspaketinden bakın :

command | ts

Veya, eğer $commandotomatik tamponlama yaparsa ( expect-devpaket gerektirir ):

unbuffer command | ts

18

Tarih komut bu bilgiyi sağlayacak

date -u
Sat Sep 10 22:39:24 UTC 2011

Böylece yapabilirsiniz

echo $(date -u) "Some message or other"

İstediğin bu muydu ?


Date komutunu kullanmak, aklımda olan türden bir şeydi, ancak bunu komut dosyasına gerçekten ekleyemiyorum, bu yüzden aradığım şey bu satırı değiştirmenin bir yolu: "script.sh >> / var / log / logfile "tarih eklemek için.
Antonius Bloch

Bu durumda betiğinizin çıktısını adlandırılmış bir boruya yönlendirin ve betiğin çıktısını alan ve bir günlük dosyasına yazmadan önce tarih ekleyen çıktıyı dinleyen bir arka plana sahip olun. Bunu yapmak için buraya yazdığım betiği büyük olasılıkla değiştirebilirsiniz . Bunu yapardım çünkü beni ilgilendirir, ancak İngiltere'de geç kaldım ve yarın erken başlıyorum.
user9517 10:11

12

Sadece yapabilirsiniz yankı günlük dosyası komut çıktılarını. yani

echo "`date -u` `./script.sh`" >> /var/log/logfile

Gerçekten çalışıyor :)

Örnek:

[sparx@E1]$ ./script.sh 
Hello Worldy
[sparx@E1]$ echo "`date -u` `./script.sh`" >> logfile.txt
[sparx@E1]$ cat logfile.txt 
Mon Sep 12 20:18:28 UTC 2011 Hello Worldy
[sparx@E1]$ 

Hmm benim için çalışmıyor.
Antonius Bloch

Komutu çalıştırdığınızda ne alıyorsunuz?
SparX 12:11

8
Bu, her satırdan önce değil, tüm '' ./script.sh '' çıktısının önüne bir zaman damgası koyar.
clacke

8

Bir Make config.shdosyası

#!/usr/bin/env bash
LOGFILE="/path/to/log.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`

Günlük dosyasını kullanmak için göndermeniz gerektiğinde

#!/usr/bin/env bash
source /path/to/config.sh

echo "$TIMESTAMP Say what you are doing" >> $LOGFILE

do_what_you_want >> $LOGFILE

Günlük dosyası gibi görünecek

2013-02-03 18:22:30 Say what you are doing

Yani tarihe göre sıralamak kolay olacak


8
'' Config.sh '', '' tarih ... '' ifadesini tam olarak bir kez, '' source ... / config.sh '' üzerinde çalıştırır.
clacke

5

Gibi demek istiyorsun:

(date && script.sh) >> /var/log/logfile

Tanrım, millet, herkes kene değiştirme işlemini yapıyor, boru adı verilen, vb. Geri dönüyor. Çok satırlı çıktı varsa ve günlük her satırda tarihle güzel görünmek zorunda kalırsa, işlevi olan adamın yasal bir durumu vardır, ancak bu çözümlerin çoğu kabuk anlambilimi kullanmayan fazladır.
cjc 12:11

8
Bu, yalnızca çalıştırma başına bir kez zaman damgası ekleyecektir script.sh. OP'nin her hat için bir zaman damgası ihtiyacı var.
Dave Forgac

1
Bu OP sorusuna cevap vermese de yine de faydalı bilgiler buldum.
Kullanıcı

4

Bunu dene

timestamp()
{
 date +"%Y-%m-%d %T"
}

Her echo komutunda bu zaman damgası işlevini çağırın:

echo "$(timestamp): write your log here" >> /var/log/<logfile>.log

@ shazbot: Düzenlemeniz için teşekkürler, bu bir yazım hatası oldu, farketmedim.
Sanjay Yadav,

4

Kabul edilen cevap https://serverfault.com/a/310104 , çok fazla satırın işlenmesi gerekiyorsa biraz yavaş olabilir, dateUbuntu’da saniyede yaklaşık 50 satıra izin veren genel işlemlerin başlaması -20 Cygwin'de.

Varsa bash, daha hızlı bir alternatif printf, %(...)Tformat belirteci ile yerleşik olacaktır . Karşılaştırmak

>> while true; do date; done | uniq -c
     47 Wed Nov  9 23:17:18 STD 2016
     56 Wed Nov  9 23:17:19 STD 2016
     55 Wed Nov  9 23:17:20 STD 2016
     51 Wed Nov  9 23:17:21 STD 2016
     50 Wed Nov  9 23:17:22 STD 2016

>> while true; do printf '%(%F %T)T\n'; done | uniq -c
  20300 2016-11-09 23:17:56
  31767 2016-11-09 23:17:57
  32109 2016-11-09 23:17:58
  31036 2016-11-09 23:17:59
  30714 2016-11-09 23:18:00

1

Awk'nin hızlı çalıştığını not edebilirsiniz,

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

yes |head -5000000 |gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' |uniq -c
 461592 [2017-02-28 19:46:44] y
 488555 [2017-02-28 19:46:45] y
 491205 [2017-02-28 19:46:46] y
 498568 [2017-02-28 19:46:47] y
 502605 [2017-02-28 19:46:48] y
 494048 [2017-02-28 19:46:49] y
 493299 [2017-02-28 19:46:50] y
 498005 [2017-02-28 19:46:51] y
 502916 [2017-02-28 19:46:52] y
 495550 [2017-02-28 19:46:53] y
  73657 [2017-02-28 19:46:54] y

Ancak, sed çok daha hızlı çalışır.

sed -e "s/^/$(date -R) /"

yes |head -5000000 |sed -e "s/^/$(date -R) /" |uniq -c
5000000 Tue, 28 Feb 2017 19:57:00 -0500 y

Bununla birlikte, daha yakından incelendiğinde, ayar zamanı değişmiyor gibi görünüyor.

vmstat 1 | sed -e "s/^/$(date -R) /"

1
Bunun nedeni, bastan "s/^/$(date -R) /"önce bir kez değerlendirme yapıp, tarihin yayınlanmasıdır. Sed statik bir dizgiden geçirilir.
Evan Benn

Düz bash: yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -cgawk'tan çok daha yavaştır. tsyardımcı program bash döngüsü ile benzer performans gösterir.
akhan

Perl: yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -cawk'den biraz daha yavaştır.
akhan

1

Günlük dosya içeriğim aşağıdadır

xiongyu@ubuntu:~/search_start_sh$ tail restart_scrape.log 

2017-08-25 21:10:09 scrape_yy_news_main.py got down, now I will restart it

2017-08-25 21:10:09 check_yy_news_warn.py got down, now I will restart it

2017-08-25 21:14:53 scrape_yy_news_main.py got down, now I will restart it

benim kabuk içeriğimin bazıları aşağıdaki gibidir

log_file="restart_scrape.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`
echo "$TIMESTAMP $search_py_file got down, now I will restart it" | tee -a $log_file 

1

Bu komut dosyası çıktıyı terminalde yazdırır ve ayrıca günlük dosyasına kaydeder.

#!/bin/bash

MY_LOG=/var/log/output.log

echolog(){
    if [ $# -eq 0 ]
    then cat - | while read -r message
        do
                echo "$(date +"[%F %T %Z] -") $message" | tee -a $MY_LOG
            done
    else
        echo -n "$(date +'[%F %T %Z]') - " | tee -a $MY_LOG
        echo $* | tee -a $MY_LOG
    fi
}

echolog "My script is starting"
whoami | echolog

Örnek çıktı:

[2017-10-29 19:46:36 UTC] - My script is starting
[2017-10-29 19:46:36 UTC] - root

ilk tarih komutunuz çift tırnak kullanmamalı, tek tırnak kullanmalı.
Jason Harrison

1

Başka bir seçenek de, kodunuzda veri çıkışı yapmak istediğiniz her defasında arayacak bir işlev ayarlamaktır:

PrintLog(){
  information=$1
  logFile=$2
  echo "$(date +'%Y-%m-%d %H:%M:%S" $information} >> $logFile
}

Daha sonra kodunuzda her zaman günlük dosyası çağrısına göndermek istersiniz.

PrintLog "Stuff you want to add..." ${LogFileVariable}

Tereyağından kıl çeker gibi....


0

Bir "sed" borusu:

script.sh | sed "s|^|$('date') :: |" >> /var/log/logfile

Diğer cevap gelince, bu sadece bir kez bash koşu tarihidir. sed, satır başına geçen süreyi güncellemiyor.
Evan Benn
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.