我有一个日志文件,我需要在添加时将时间戳附加到每一行。因此,我正在寻找将时间戳附加到日志行中的每个条目并且可以作为 cron 作业运行的脚本。
Dmi*_*try 19
$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log
Run Code Online (Sandbox Code Playgroud)
这个怎么运作:
cat
读取调用的文件input.log
并将其打印到其标准输出流。
通常标准输出连接到终端,但是这个小脚本包含|
所以 shell 将标准输出重定向cat
到sed
.
sed
读取数据(cat
产生它),处理它(根据-e
选项提供的脚本),然后将其打印到其标准输出。该脚本"s/^/$(date -R) /"
意味着将行的每个开头替换为由date -R
命令生成的文本(替换命令的一般结构是:)s/pattern/replace/
。
然后根据>>
bash
将输出重定向sed
到一个名为output.log
(>
表示替换文件内容并>>
表示追加到末尾) 的文件。
问题是$(date -R)
运行脚本时评估一次,因此它将在每行的开头插入当前时间戳。当前时间戳可能与生成消息的时刻相差甚远。为了避免它,您必须在将消息写入文件时处理消息,而不是使用 cron 作业。
上面描述的标准流重定向称为pipe。您不仅可以|
在脚本中的命令之间重定向它,还可以通过FIFO 文件(又名命名管道)重定向它。一个程序将写入文件,另一个程序将读取数据并在第一次发送时接收它。
选择一个例子:
$ mkfifo foo.log.fifo
$ while true; do cat foo.log.fifo | sed -e "s/^/$(date -R) /" >> foo.log; done;
# have to open a second terminal at this point
$ echo "foo" > foo.log.fifo
$ echo "bar" > foo.log.fifo
$ echo "baz" > foo.log.fifo
$ cat foo.log
Tue, 20 Nov 2012 15:32:56 +0400 foo
Tue, 20 Nov 2012 15:33:27 +0400 bar
Tue, 20 Nov 2012 15:33:30 +0400 baz
Run Code Online (Sandbox Code Playgroud)
这个怎么运作:
mkfifo
创建命名管道
while true; do sed ... ; done
运行一个无限循环,并在每次迭代时sed
重定向foo.log.fifo
到其标准输入;sed
阻止等待输入数据,然后处理接收到的消息并将其打印到重定向到foo.log
.
此时你必须打开一个新的终端窗口,因为循环占用了当前终端。
echo ... > foo.log.fifo
将消息打印到重定向到 fifo 文件的标准输出并sed
接收它并处理并写入常规文件。
重要的一点是fifo,就像任何其他管道如果其一侧未连接到任何进程就没有意义一样。如果您尝试写入管道,当前进程将阻塞,直到有人读取管道另一侧的数据。如果您想从管道中读取数据,该进程将阻塞,直到有人将数据写入管道。sed
上面示例中的循环不执行任何操作(休眠),直到您执行echo
.
对于您的特定情况,您只需将应用程序配置为将日志消息写入 fifo 文件。如果您无法配置它 - 只需删除原始日志文件并创建一个 fifo 文件。但请再次注意,如果sed
循环由于某种原因而终止 - 您的程序将在尝试访问write
文件时被阻止,直到有人read
从 fifo 中删除。
好处是在程序将其写入文件时评估当前时间戳并将其附加到消息。
tailf
为了使写入日志和处理更加独立,您可以使用两个带有tailf
. 应用程序将消息写入原始文件,其他进程读取新行(跟随异步写入)并通过写入第二个文件处理数据。
让我们举个例子:
# will occupy current shell
$ tailf -n0 bar.raw.log | while read line; do echo "$(date -R) $line" >> bar.log; done;
$ echo "foo" >> bar.raw.log
$ echo "bar" >> bar.raw.log
$ echo "baz" >> bar.raw.log
$ cat bar.log
Wed, 21 Nov 2012 16:15:33 +0400 foo
Wed, 21 Nov 2012 16:15:36 +0400 bar
Wed, 21 Nov 2012 16:15:39 +0400 baz
Run Code Online (Sandbox Code Playgroud)
这个怎么运作:
运行tailf
将遵循写入bar.raw.log
并将它们打印到重定向到无限while read ... echo
循环的标准输出的进程。这个循环执行两个操作:从标准输入读取数据到一个被调用的缓冲区变量line
,然后将生成的时间戳和以下缓冲数据写入到bar.log
.
写一些消息到bar.raw.log
. 您必须在单独的终端窗口中执行此操作,因为第一个将被占用tailf
,它将跟随写入并完成其工作。非常简单。
优点是如果你杀死了你的应用程序不会阻塞tailf
。缺点是不太准确的时间戳和重复的日志文件。
您可以使用以下ts
perl 脚本moreutils
:
$ echo test | ts %F-%H:%M:%.S
2012-11-20-13:34:10.731562 test
Run Code Online (Sandbox Code Playgroud)