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

script.sh >> /var/log/logfile


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

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


我可以使用任何柔术吗?

评论

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

有关awk / gawk的解决方案,请参见:stackoverflow.com/questions/21564/…

这是bash日志记录的全面实现:github.com/codeforester/base/blob/master/lib/stdlib.sh

最好的本地答案是@ChuckCottrill的serverfault.com/a/835534/137665。 script.sh | gawk'{print strftime(“ [%Y-%m-%d%H:%M:%S]”),$ 0}'>> / var / log / logfile

#1 楼

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

./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


评论


@Nils是一个技巧,可以防止读取在行的开始和行处修剪空格。它将IFS(bash的内部字段分隔符,基本上是空白字符列表)设置为空,以供读取命令使用。

–戈登·戴维森(Gordon Davisson)
2011-09-15 21:43

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

–指甲
2011年9月16日在20:47

@Nils并不是完全防弹,因为echo的某些实现会解释转义序列。如果您真的希望它不会弄乱内容(除了添加日期),请用printf“%s%s \ n”“ $(date)”“ $ line”替换echo命令。

–戈登·戴维森(Gordon Davisson)
2011年9月17日下午2:31

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

– Pablo A
17年7月29日在1:40



尽管此脚本可以按预期工作,但它会为每个日志行产生一个新进程(执行日期),这可能是一个很大的缺点,具体取决于您的计算机和日志量。我宁愿建议使用ts(如果可用),请参阅@willem的答案

– Michael Schaefers
18年5月9日在13:20

#2 楼

请参阅Ubuntu ts软件包中的moreutils

command | ts


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

unbuffer command | ts


#3 楼

date命令将提供该信息

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


,因此您可以

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


是您想要的吗?

评论


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

– Antonius Bloch
2011-09-10 21:53

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

–user9517
2011-09-10 22:12



#4 楼

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

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


评论


执行命令时您会得到什么?

– SparX
2011年9月12日20:15在

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

–clacke
2015年3月9日15:01

#5 楼

制作一个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


,因此按日期排序很容易

评论


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

–clacke
2015年3月9日15:03

#6 楼

如果必须处理很多行,则可接受的答案https://serverfault.com/a/310104可能会有点慢,而启动date进程的开销允许在Ubuntu中每秒大约50行,而大约Cygwin 10-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


评论


这个答案值得更多关注。即使在当今的计算机上使用外部程序日期现在可能是这样的性能问题,但当工具内部包含所有内容时,最好不要使更多的工具复杂化。另外,此答案还提供了一个简单的本地可重复性的性能度量(在我的机器上,我的速度为每秒700-1000,每秒为150k-170k)。更多的答案应该是这样的质量。

–StéphaneGourichon
19年11月22日在15:21

@StéphaneGourichon实际上,在某些情况下,它仍然可以对性能产生巨大的影响。例如。我使用这种结构通过一些程序将时间信息添加到stdout中。虽然是真的约会;完成| uniq -c。如果程序每秒产生数百行,则每个调用日期都会降低性能,而使用内置函数则不会。尽管有些奇怪,但是现在即使是内置函数,对于我来说,每个uniq -c也只能产生约4000行。。。可能是那时我在Linux上进行了测试。

– kdb
19年11月23日在21:59



是的,我们同意,没有重复的外部程序会更快。当性能非常重要时,没有重复的bash构造会更快。基于GNU awk的解决方案可能提供最好的解决方案,请参见@ChuckCottrill的答案serverfault.com/a/835534/137665在我的机器上,通过替换yes | head -5000000 |获得3.5倍的速度增益。虽然是真的做printf'%(%F%T)T \ n';完成| uniq -c和yes | head -5000000 | gawk'{print strftime(“ [%Y-%m-%d%H:%M:%S]”),$ 0}'>> / var / log / logfile。

–StéphaneGourichon
19年11月25日在19:17



#7 楼

您的意思是:

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


评论


我的上帝,人民,每个人都在做反勾替换,命名管道等。只需将date命令和脚本括在括号中!如果有多行输出,并且具有日志功能,并且每行的日期看起来都很漂亮,那么具有此功能的人就会很在意,但是这些解决方案中的大多数都是过时的,没有使用shell语义。

– cjc
2011年9月12日21:11在

每次执行script.sh只会添加一次时间戳。 OP每行需要一个时间戳。

–戴夫·福加克
2012年10月10日14:10

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

–用户
2012年11月2日在20:14

#8 楼

试试这个

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


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

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


评论


@ shazbot:谢谢编辑,那是一个错字,我没有注意到。

– Sanjay Yadav
15年6月15日在7:08

#9 楼

格式化为适合该问题的简短答案

script.sh | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), 
gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), 
yes |head -5000000 |gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), 
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
}' |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
}'
}' >> /var/log/logfile


说明

awk运行速度很快,并且能够单独用作Unix管道过滤器和打印日期。

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


对其进行基准测试:

q4312078q

其他信息

Sed看起来运行得更快,

q4312078q

但是,仔细检查后发现,设置似乎并没有改变时间,

q4312078q

因为date(顺便说来比较慢)仅被调用一次。

评论


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

–埃文·本恩
18年11月8日在22:34

普通重击:是|头-5000000 |边读边;做echo $((SECONDS));完成| uniq -c比gawk慢得多。 ts实用程序的性能与bash循环相似。

– akhan
19-09-27在23:43



Perl:是| head -5000000 | perl -ne'打印本地时间。“ \ t”。$ _'| uniq -c,它比awk稍慢。

– akhan
19-09-28在0:06



#10 楼

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

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


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

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


简单易用....

评论


您缺少亲密朋友

– OneCricketeer
20年5月6日在17:18

#11 楼

以下是我的日志文件内容

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


我的一些shell内容如下

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 


#12 楼

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

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


评论


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

–詹森·哈里森(Jason Harrison)
19年3月29日在21:00

#13 楼

我只是这样做(buddy变量只是一个示例,您可以在其中放置任何内容):
#!/bin/bash
now=$( date +%Y%m%d-%H%M-%S )
buddy=`cat /proc/buddyinfo | grep Normal`
echo "$now, $buddy" >> /home/myuser/buddyinfo-logger.log


这非常有效。

#14 楼

我已经注意到,将xargs与printf一起使用效果很好且速度很快。
 timestamp="$(date -Iseconds)"
ls | xargs -d '\n' -l printf '%s: %s' "$timestamp" 1>&2
 

我写到stderr只是为了不污染stdout 。
我制作了一个用bash编写的日志记录实用程序,可在我的bash脚本中使用它:
https://github.com/bas080/logger
它具有比上述示例更多的功能。

#15 楼

在脚本的开头添加以下内容:
#!/bin/bash
set -x
PS4='[\D{%d.%m.%y} \t]'

这将为每个命令添加日期和时间,并且也将其写出-例如:
回显“ GIT_BRANCH:$ GIT_BRANCH”
[11.12.20 12:50:46] echo'GIT_BRANCH:master'
引用和描述:
bash选项:
https://tldp.org/LDP/abs/ html / options.html
Bash PS变量:
https://linoxide.com/how-tos/change-bash-prompt-variable-ps1/#:~:text=PS1%3A%20environment %20variable%20that%20contains,long%20command%20in%20many%20lines。

#16 楼

用管道输送“ sed”:

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


评论


至于其他答案,这只是bash运行日期一次。 sed不会更新每行的时间。

–埃文·本恩
18年11月8日在22:35