如何在bash脚本日志中添加时间戳?


94

我有一个不断运行的脚本,我输出到日志文件:

script.sh >> /var/log/logfile

我想在附加到日志的每一行之前添加一个时间戳。喜欢:

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

我可以使用柔术吗?


2
看到这个问题。 serverfault.com/questions/80749/…。这里有几个答案。
Zoredache

有关awk / gawk解决方案,请参阅:stackoverflow.com/questions/21564/…– 2012
用户

Answers:


88

您可以通过前缀当前日期和时间的循环来传递脚本的输出:

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

如果您将经常使用它,可以很容易地创建一个bash函数来处理循环:

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是防止read在行首和行中修剪空格的一种技巧。它将命令的IFS(bash的Internal Field Separator,基本上是空白字符列表)设置为空read
戈登·戴维森

2
...并且-r忽略转义字符“ \”。这在所有情况下都应该确实有效-脚本编写非常出色。
Nils

7
@Nils并不是完全防弹,因为某些echo解释转义序列的实现。如果您真的希望它不干扰内容(除了添加日期),请将该echo命令替换为printf "%s %s\n" "$(date)" "$line"
Gordon Davisson

4
您可能对符合ISO-8601的日期/时间戳感兴趣:date -u +"%Y-%m-%dT%H:%M:%SZ"或更漂亮date +"%Y-%m-%d %T"
巴勃罗A

1
尽管此脚本可以按预期工作,但它会date每条日志行生成一个新进程(execute ),根据您的计算机和日志量的不同,这可能是一个巨大的缺陷。我宁愿建议使用(ts如果有的话),请参阅@willem的答案
Michael Schaefers

56

ts从Ubuntu moreutils软件包中查看:

command | ts

或者,是否进行$command自动缓冲(需要expect-dev包装):

unbuffer command | ts

18

日期的命令将提供信息

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

所以你可以

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

那是你想要的吗?


使用date命令是我的初衷,但我无法真正将其添加到脚本本身,因此我正在寻找一种更改此行的方法:“ script.sh >> / var /日志/日志文件”添加日期。
安东尼·布洛赫

在这种情况下,将脚本的输出重定向到命名管道,并让守护进程监听输出,该守护程序接受脚本输出并在写入日志文件之前添加日期。您可能可以修改我在此处编写脚本来执行此操作。我会这样做,因为它使我感兴趣,但它在英国很晚,明天我会早一点开始。
user9517 2011年

12

您可以简单地将命令输出显到日志文件。即

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

真的行 :)

例:

[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]$ 

嗯,对我不起作用。
Antonius Bloch

执行命令会得到什么?
SparX

8
这会将时间戳记放在``./script.sh''的整个输出之前,而不是每行之前。
clacke 2015年

8

制作config.sh文件

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

当您需要发送到日志文件时使用

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

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

do_what_you_want >> $LOGFILE

日志文件看起来像

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

所以按日期排序很容易


8
您的“ config.sh”将在“ source ... / config.sh”上仅运行一次“ date”。
clacke 2015年

5

您的意思是:

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

我的天哪,人们,每个人都在做反刻度线替换,命名管道等。只需将date命令和脚本括在括号中!如果有多行输出并且日志需要在每行上显示日期,则具有该功能的人会很合法,但是这些解决方案中的大多数都是过时的,没有使用shell语义。
cjc 2011年

8
每次执行只会增加一次时间戳script.sh。OP每行需要一个时间戳。
Dave Forgac '10 -10-10

1
尽管这不能回答OP问题,但我仍然发现它很有用。
用户


4

如果必须处理很多行,则可接受的答案https://serverfault.com/a/310104可能会有点慢,启动该date过程的开销允许在Ubuntu中每秒大约50行,而大约只有10行Cygwin中的-20。

如果bash可以假设更快的替代方案将是printf其内置的%(...)T格式说明。相比

>> 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运行速度很快,

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

但是sed的运行速度更快,

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

但是,仔细检查,设定似乎不会改变时间,

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

1
这是因为它是"s/^/$(date -R) /"sed前一次bash评估和运行日期。Sed传递了一个静态字符串。
埃文·本

普通打击:yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -c比gawk慢得多。ts实用程序的性能与bash循环相似。
akhan

Perl:yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -c比awk慢一点。
akhan

1

以下是我的日志文件内容

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

我的一些外壳内容如下

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

该脚本在终端中打印输出,并保存在日志文件中。

#!/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

样本输出:

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

您的第一个日期命令应使用单引号而不是双引号。
杰森·哈里森

1

另一种选择是设置一个函数,以在每次要在代码中输出数据时调用:

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

然后,每次在您的代码中要将其发送到日志文件调用

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

十分简单....


0

用管道发送“ sed”:

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

至于其他答案,这只是一次bash运行日期。sed不会更新每行的时间。
埃文·本
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.