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

Ant*_*och 124 linux shell bash logging

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

script.sh >> /var/log/logfile
Run Code Online (Sandbox Code Playgroud)

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

Sat Sep 10 21:33:06 UTC 2011 The server has booted up.  Hmmph.
Run Code Online (Sandbox Code Playgroud)

有什么柔术可以用吗?

Gor*_*son 110

您可以通过带有当前日期和时间前缀的循环来管道脚本的输出:

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

如果你经常使用它,很容易制作一个 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
Run Code Online (Sandbox Code Playgroud)

  • @Nils 它不是完全防弹的,因为 `echo` 的一些实现会解释转义序列。如果你*真的*不想弄乱内容(除了添加日期),请将 `echo` 命令替换为 `printf "%s %s\n" "$(date)" "$line"` (8认同)
  • 您可能对 [ISO-8601 兼容](/sf/answers/505147611/) 日期/时间戳感兴趣:`date -u +"%Y-%m-%dT%H:%M :%SZ"` 或者更漂亮的`date +"%Y-%m-%d %T"`。 (4认同)
  • @Nils 防止“读取”在行首和行尾修剪空白是一个技巧。它为 `read` 命令将 IFS(bash 的内部字段分隔符,基本上是一个空白字符列表)设置为空。 (3认同)
  • ...并且 -r 忽略转义字符“\”。这应该在所有情况下都有效 - 很棒的脚本。 (2认同)
  • 虽然此脚本按预期工作,但它会为 _each_ 日志行生成一个新进程(执行 `date`),这可能是一个巨大的缺点,具体取决于您的机器和日志数量。如果可用,我宁愿建议使用`ts`,请参阅@willem 的答案 (2认同)

Wil*_*lem 75

ts从 Ubuntumoreutils包中查看:

command | ts
Run Code Online (Sandbox Code Playgroud)

或者,如果$command自动缓冲(需要expect-dev包):

unbuffer command | ts
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考,`unbuffer` 位于 Arch Linux 上的“expect”包中。 (2认同)

use*_*517 33

日期的命令将提供信息

date -u
Sat Sep 10 22:39:24 UTC 2011
Run Code Online (Sandbox Code Playgroud)

这样你就可以

echo $(date -u) "Some message or other"
Run Code Online (Sandbox Code Playgroud)

那是你想要的吗?


Spa*_*arX 11

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

echo "`date -u` `./script.sh`" >> /var/log/logfile
Run Code Online (Sandbox Code Playgroud)

真的行 :)

例子:

[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]$ 
Run Code Online (Sandbox Code Playgroud)

  • 这会在 ''./script.sh'' 的整个输出之前放置一个时间戳,而不是在每一行之前。 (14认同)

小智 10

制作config.sh文件

#!/usr/bin/env bash
LOGFILE="/path/to/log.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`
Run Code Online (Sandbox Code Playgroud)

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

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

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

do_what_you_want >> $LOGFILE
Run Code Online (Sandbox Code Playgroud)

日志文件看起来像

2013-02-03 18:22:30 Say what you are doing
Run Code Online (Sandbox Code Playgroud)

所以按日期排序会很容易

  • 您的 ''config.sh'' 将在 ''source .../config.sh'' 上只运行一次 ''date''。 (11认同)

kdb*_*kdb 7

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

什么时候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
Run Code Online (Sandbox Code Playgroud)

评论。在我目前的 OpenSuse 工作 PC(2021 年 7 月)上,性能显着提高,每秒执行 1200 行,date使用printf. 不完全清楚,与 5 年前的笔记本电脑相比,这种特殊的性能如何提高了近两个数量级。


Chu*_*ill 6

简短答案的格式适合问题

script.sh | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' >> /var/log/logfile
Run Code Online (Sandbox Code Playgroud)

解释

awk运行速度快能够作为 Unix 管道过滤器工作自行打印日期。

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

让我们对其进行基准测试:

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
Run Code Online (Sandbox Code Playgroud)

附加信息

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
Run Code Online (Sandbox Code Playgroud)

然而,仔细观察,设置似乎并没有改变时间,

vmstat 1 | sed -e "s/^/$(date -R) /"
Run Code Online (Sandbox Code Playgroud)

因为date(顺便说一句,速度较慢)只被调用一次。


cjc*_*cjc 5

你的意思是:

(date && script.sh) >> /var/log/logfile
Run Code Online (Sandbox Code Playgroud)

  • 这只会在每次执行 `script.sh` 时添加一次时间戳。OP 每行需要一个时间戳。 (9认同)
  • 虽然这不能回答 OP 问题,但我仍然发现它是有用的信息。 (2认同)

小智 5

尝试这个

timestamp()
{
 date +"%Y-%m-%d %T"
}
Run Code Online (Sandbox Code Playgroud)

在每个 echo 命令中调用这个时间戳函数:

echo "$(timestamp): write your log here" >> /var/log/<logfile>.log
Run Code Online (Sandbox Code Playgroud)