重定向到日志文件时如何在 stdout 和 stderr 输出前加上时间戳?
How to prepend stdout and stderr output with timestamp when redirecting into log files?
在 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 命令而不需要额外的包。
在 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)
在任何 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]"),[=11=]}'; }
例子
例如,让我们创建命令 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_pipe
。 log_pipe
的标准输出重定向到 $stdout_log
,log_pipe
的标准错误重定向到 $stderr_log
。 问题是 cmd
的标准错误永远不会被重定向。直达航站楼。
例如,考虑这个 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
.
的错误消息
这有效,但我的命令必须在后台 运行 因为它在初始化脚本中,因此我必须这样做:
({ cmd | log_pipe >>stdout.log; } 2>&1 | log_pipe >>stderr.log) &
echo $! > "$pid_file"
对吗?
但我认为在这种情况下 $pid_file 中的 pid 不是 $cmd 的 pid...
在 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 命令而不需要额外的包。
在 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)
在任何 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]"),[=11=]}'; }
例子
例如,让我们创建命令 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_pipe
。 log_pipe
的标准输出重定向到 $stdout_log
,log_pipe
的标准错误重定向到 $stderr_log
。 问题是 cmd
的标准错误永远不会被重定向。直达航站楼。
例如,考虑这个 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
.
这有效,但我的命令必须在后台 运行 因为它在初始化脚本中,因此我必须这样做:
({ cmd | log_pipe >>stdout.log; } 2>&1 | log_pipe >>stderr.log) &
echo $! > "$pid_file"
对吗?
但我认为在这种情况下 $pid_file 中的 pid 不是 $cmd 的 pid...