关于shell:是否有Unix实用程序在stdin之前添加时间戳?

关于shell:是否有Unix实用程序在stdin之前添加时间戳?

Is there a Unix utility to prepend timestamps to stdin?

我最终使用Python为此编写了一个快速的小脚本,但是我想知道是否有一个实用程序可以将文本输入到每行的前面,在我的特定情况下是时间戳,您可以在其中输入文本。 理想情况下,使用方式如下:

1
cat somefile.txt | prepend-timestamp

(在您回答sed之前,我尝试过此操作:

1
cat somefile.txt | sed"s/^/`date`/"

但这只会在执行sed时对date命令执行一次评估,因此同一时间戳会错误地添加到每一行。)


来自moreutils的ts将为您提供的每一行输入时间戳。您也可以使用strftime对其进行格式化。

1
2
3
4
5
$ echo 'foo bar baz' | ts
Mar 21 18:07:28 foo bar baz
$ echo 'blah blah blah' | ts '%F %T'
2012-03-21 18:07:30 blah blah blah
$

要安装它:

1
sudo apt-get install moreutils

可以尝试使用awk

1
<command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; fflush(); }'

您可能需要确保产生行缓冲输出,即它在每行之后刷新其输出流; awk添加的时间戳记是行尾出现在其输入管道上的时间。

如果awk显示错误,请尝试使用gawk


注释,可以通过该链接获得,也可以在Debian devscripts软件包中作为annotate-output获得。

1
2
3
4
5
6
7
8
9
$ echo -e"a
b
c"> lines
$ annotate-output cat lines
17:00:47 I: Started cat lines
17:00:47 O: a
17:00:47 O: b
17:00:47 O: c
17:00:47 I: Finished with exitcode 0

将给出的答案简化为最简单的答案:

1
unbuffer $COMMAND | ts

在Ubuntu上,它们来自Expect-dev和moreutils软件包。

1
sudo apt-get install expect-dev moreutils

这个怎么样?

1
cat somefile.txt | perl -pne 'print scalar(localtime()),"";'

从您希望获得实时时间戳的角度来看,也许您想对日志文件或其他内容进行实时更新?也许

1
tail -f /path/to/log | perl -pne 'print scalar(localtime()),"";' > /path/to/log-with-timestamps

只是把它扔在那里:daemontools中有一对实用程序,称为tai64n和tai64nlocal,用于在时间戳记之前记录消息。

例:

1
cat file | tai64n | tai64nlocal


Kieron的答案是迄今为止最好的答案。如果由于第一个程序正在缓冲它而遇到问题,则可以使用unbuffer程序:

1
unbuffer <command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; }'

大多数Linux系统默认安装了它。如果您需要自己构建它,则它是Expect包的一部分

http://expect.nist.gov


使用read(1)命令一次从标准输入中读取一行,然后使用date(1)以您选择的格式输出以日期开头的行。

1
2
3
4
5
6
7
$ cat timestamp
#!/bin/sh
while read line
do
  echo `date` $line
done
$ cat somefile.txt | ./timestamp

我不是Unix专家,但我认为您可以使用

1
gawk '{print strftime("%d/%m/%y",systime()) $0 }' < somefile.txt

1
2
3
4
5
6
7
#! /bin/sh
unbuffer"$@" | perl -e '
use Time::HiRes (gettimeofday);
while(<>) {
        ($s,$ms) = gettimeofday();
        print $s ."." . $ms ."" . $_;
}'

1
$ cat somefile.txt | sed"s/^/`date`/"

您可以执行此操作(使用gnu / sed):

1
2
$ some-command | sed"x;s/.*/date +%T/e;G;s/
/ /g"

例:

1
2
3
4
$ { echo 'line1'; sleep 2; echo 'line2'; } | sed"x;s/.*/date +%T/e;G;s/
/ /g"
20:24:22 line1
20:24:24 line2

当然,您可以使用计划日期的其他选项。只需将date +%T替换为您需要的内容即可。


混合以上natevw和Frank Ch。的答案。艾格勒

它具有毫秒数,比每次调用外部date命令都要好,并且可以在大多数服务器中找到perl。

1
2
3
4
5
6
tail -f log | perl -pne '
  use Time::HiRes (gettimeofday);
  use POSIX qw(strftime);
  ($s,$ms) = gettimeofday();
  print strftime"%Y-%m-%dT%H:%M:%S+$ms", gmtime($s);
  '

带有刷新和循环读取的替代版本:

1
2
3
4
5
6
7
tail -f log | perl -pne '
  use Time::HiRes (gettimeofday); use POSIX qw(strftime);
  $|=1;
  while(<>) {
    ($s,$ms) = gettimeofday();
    print strftime"%Y-%m-%dT%H:%M:%S+$ms $_", gmtime($s);
  }'

这是我的awk解决方案(来自Windows / XP系统,该系统在C: bin目录中安装了MKS工具)。它的设计目的是将当前日期和时间以mm / dd hh:mm的形式添加到在读取每一行时已从系统中获取了该时间戳记的每一行的开头。当然,您可以使用BEGIN模式获取一次时间戳并将该时间戳添加到每条记录中(全部相同)。我这样做是为了将生成的日志文件标记为生成日志消息时带有时间戳的stdout。

/"pattern"/ "C\:\\\\bin\\\\date '+%m/%d %R'" | getline timest

print timestamp, $0;

其中"模式"是要在输入行中匹配的字符串或正则表达式(不带引号),如果希望匹配所有输入行,则为可选。

这也应该在Linux / UNIX系统上工作,只需摆脱C :\ bin \

1
            "date '+%m/%d %R'" | getline timest

当然,这假定命令" date"将您带到标准Linux / UNIX date display / set命令,而没有特定的路径信息(即,您的环境PATH变量已正确配置)。


caerwyn的答案可以作为子例程运行,这将阻止每行新的进程:

1
2
3
4
5
6
7
8
timestamp(){
   while read line
      do
         echo `date` $line
      done
}

echo testing 123 |timestamp

免责声明:我提出的解决方案不是Unix内置实用程序。

几天前我遇到了类似的问题。我不喜欢上述解决方案的语法和局限性,因此我很快在Go中组合了一个程序来为我完成工作。

您可以在此处检查该工具:preftime

GitHub项目的"发行版"部分中有针对Linux,MacOS和Windows的预构建可执行文件。

该工具处理不完整的输出行,并且(从我的角度来看)具有更紧凑的语法。

| preftime

这并不理想,但是我会分享它,以防它对某人有所帮助。


在OSX上使用datetrxargs进行操作:

1
2
3
alias predate="xargs -I{} sh -c 'date +"%Y-%m-%d %H:%M:%S" | tr "
" " "; echo "{}"'"
<command> | predate

如果要毫秒:

1
2
alias predate="xargs -I{} sh -c 'date +"%Y-%m-%d %H:%M:%S.%3N" | tr "
" " "; echo "{}"'"

但是请注意,在OSX上,date不会为您提供%N选项,因此您需要安装gdate(brew install coreutils),然后最终到达此位置:

1
2
alias predate="xargs -I{} sh -c 'gdate +"%Y-%m-%d %H:%M:%S.%3N" | tr "
" " "; echo "{}"'"


如果您要附加的值在每一行都相同,请使用该文件启动emacs,然后:

Ctrl +

在文件的开头(以标记该位置),然后向下滚动到最后一行的开头(Alt +>将转到文件的末尾...这可能也涉及Shift键,然后按Ctrl + a转到该行的开头),然后:

Ctrl + x r t

这是要在您刚刚指定的矩形(宽度为0的矩形)上插入的命令。

2008-8-21 6:45 PM

或任何您想添加的内容...然后,您将看到该文本添加到0宽度矩形内的每一行。

更新:我只是意识到您不希望使用相同的日期,所以这将无法工作...尽管您可以使用稍微复杂一些的自定义宏在emacs中执行此操作,但是仍然可以进行这种矩形编辑很高兴知道...


推荐阅读