在重定向到日志文件时,如何在带有时间戳的stdout和stderr输出之前添加前缀?

时间:2019-07-05 05:12:10

标签: shell logging pipe stdout init

在Linux中,我正在初始化脚本(SysVInit)中启动名为$cmd的程序。我已经将$cmd的stdout和stderr重定向到名为$stdout_log$stderr_log的两个不同的日志文件中。现在,我还想在打印到日志文件的每一行之前添加一个时间戳。

我试图编写一个名为log_pipe的函数,如下所示:

log_pipe() {
    while read line; do
        echo [$(date +%Y-%m-%d\ %H:%M:%S)] "$line"
    done
}

然后将我的脚本输出通过管道传递到此函数中,然后将其重定向到日志文件,如下所示:

$cmd | log_pipe >> "$stdout_log" 2>> "$stderr_log" &

我得到的是一个空的$stdout.log(标准输出),这应该没问题,因为$cmd通常不打印任何内容。还有一个$stderr.log文件,只有时间戳,没有错误文本。

我的错误推理在哪里?

PS:因为问题存在于初始化脚本中,所以我只想使用基本的Shell命令,而没有多余的软件包。

2 个答案:

答案 0 :(得分:2)

在任何POSIX Shell中,尝试:

{ cmd | log_pipe >>stdout.log; } 2>&1 | log_pipe >>stderr.log

此外,如果您有GNU awk(有时称为gawk),那么log_pipe可以变得更简单,更快:

log_pipe() {  awk '{print strftime("[%Y-%m-%d %H:%M:%S]"),$0}'; }

示例

作为示例,让我们创建命令cmd

cmd() { echo "This is out"; echo "This is err">&2; }

现在,让我们运行命令并查看输出文件:

$ { cmd | log_pipe >>stdout.log; } 2>&1 | log_pipe >>stderr.log
$ cat stdout.log
[2019-07-04 23:42:20] This is out
$ cat stderr.log
[2019-07-04 23:42:20] This is err

问题

cmd | log_pipe >> "$stdout_log" 2>> "$stderr_log"

以上内容将标准输出从cmd重定向到log_pipelog_pipe的标准输出重定向到$stdout_loglog_pipe的标准输出重定向到$stderr_log问题是cmd的stderr从未重定向。它直接进入终端。

作为示例,请考虑以下cmd

cmd() { echo "This is out"; echo "This is err">&2; }

现在,让我们运行命令:

$ cmd | log_pipe >>stdout.log 2>>stderr.log
This is err

我们可以看到This is err没有发送到文件stderr.log。而是,它出现在终端上。 log_pipe从未见过。 stderr.log仅捕获来自log_pipe的错误消息。

答案 1 :(得分:1)

在Bash中,您还可以使用进程替换重定向到子Shell:

logger.sh

#!/bin/bash
while read -r line; do
   echo "[$(date +%Y-%m-%d\ %H:%M:%S)] $line"
done

重定向

cmd > >(logger.sh > stdout.log) 2> >(logger.sh > stderr.log)