现在我正在使用 exec 将 stderr 重定向到错误日志
exec 2>> ${errorLog}
唯一的缺点是我必须以时间戳开始每次运行,因为 exec 只是将文本直接推送到日志文件中。有没有办法重定向 stderr 但允许我向它附加文本,例如时间戳?
这很有趣。我问过一个非常了解 bash 的人,他这样告诉我:
foo() { while IFS='' read -r line; do echo "$(date) $line" >> file.txt; done; };
首先,它创建了一个从标准输入读取一行原始输入的函数,而对 IFS 的赋值使其不会忽略空白。读取一行后,它会在输出前附加适当的数据。然后你必须告诉 bash 将 stderr 重定向到该函数中:
exec 2> >(foo)
您写入 stderr 的所有内容现在都将通过 foo 函数。请注意,当您在交互式 shell 中执行此操作时,您将不会再看到提示,因为它已打印到 stderr,并且 foo 中的读取是行缓冲的 :)
你可以简单地使用:
exec 1> >( sed "s/^/$(date '+[%F %T]'): /" | tee -a ${LOGFILE}) 2>&1
这不会完全解决您关于提示未显示的问题(它会在短时间内显示,但不是实时的,因为管道会缓存一些数据......),但会在标准输出和中显示输出 1:1文件。
唯一的问题是,我无法解决的是,从一个函数中执行此操作,因为这会打开一个子shell,其中 exec 对主程序无用......
此示例重定向 stdout 和 stderr 而不会丢失原始 stdout 和 stderr。stdout 处理程序中的错误也会记录到 stderr 处理程序。文件描述符保存在变量中并在子进程中关闭。Bash 很小心,不会发生碰撞。
#! /bin/bash
stamp ()
{
local LINE
while IFS='' read -r LINE; do
echo "$(date '+%Y-%m-%d %H:%M:%S,%N %z') $$ $LINE"
done
}
exec {STDOUT}>&1
exec {STDERR}>&2
exec 2> >(exec {STDOUT}>&-; exec {STDERR}>&-; exec &>> stderr.log; stamp)
exec > >(exec {STDOUT}>&-; exec {STDERR}>&-; exec >> stdout.log; stamp)
for n in $(seq 3); do
echo loop $n >&$STDOUT
echo o$n
echo e$n >&2
done
这需要当前的 Bash 版本,但由于Shellshock,现在人们可以依赖它。
cat q23123 2> tmp_file ;cat tmp_file | sed -e "s/^/$(date '+[%F %T]'): /g" >> output.log; rm -f tmp_file