将 stderr 重定向到文件并在每一行前面加上一个字符串

将 stderr 重定向到文件并在每一行前面加上一个字符串

我想将命令 stderr 重定向到文件,同时在它们前面加上字符串。

exec >&2 "$log_file"
command

预期的日志文件:

2021-07-13 09:34:03+07:00 [stderr] error lines ...
...

时间戳只是一个示例。我可能会为其他脚本使用其他东西。

我想用这个:

command | xargs -n1 printf '[%s] %s\n' "`date --rfc-3339=s`" 2>> "$log_file"

但这将覆盖管道命令的退出状态。而且这非常慢。

我记得在bash(或其他一些 shell)中,我可以使用exec 2>> "$log_file".但后来我不知道如何使用exec前置命令输出。

答案1

在 bash 中,这相当简单:

exec 2> >(perl -MDate::Format -pe 's/^/time2str("%Y-%m-%d %H:%M:%S%z [stderr] ",time)/e' > /var/log/some.log)

您可以将 Perl 单行代码转换为独立脚本:

#!/usr/bin/perl
use Date::Format;
while(<>) {
  s/^/time2str("%Y-%m-%d %H:%M:%S%z [stderr] ",time)/e;
  print;
}

比如说,将其另存为,/usr/local/bin/timestamp-text并使其可执行chmod +x /usr/local/bin/timestamp-text。然后你可以写成exec

exec 2> >(/usr/local/bin/timestamp-text > /var/log/some.log)

在其他类似 Bourne 的 shell 中,您不能使用exec重定向到进程替换,您必须使用 fifo。我不想再次重写相同的答案,所以我只想向您指出我为类似问题编写的另一个答案:https://unix.stackexchange.com/a/644862/7696

顺便说一句,timestamp-text脚本(或单行版本)可以用您喜欢的任何语言编写,只要它具有良好的日期格式化功能(大多数语言都具有)。它需要查询它修改的每个输入行的当前时间,而不仅仅是第一次运行时的时间(否则,您可能只使用/bin/date

注意:日期格式模块位于libtimedate-perldebian 的包中。该软件包还包含Date::ParseDate::LanguageTime::Zone模块。它也应该作为大多数其他发行版的软件包提供,否则使用cpan.


更新

我只记得有一个名为 的程序ts就是专门做这种时间戳的,所以不需要编写自己的 perl 或任何脚本。它可以在更多实用程序包裹。

exec 2> >(ts "%Y-%m-%d %H:%M:%S%z [stderr]" > /var/log/some.log)

然而,它perl本身就是一个脚本,需要Getopt::长要安装的模块,并且(取决于您使用的命令行选项)可能还需要Date::Parse时间::持续时间,和/或时间::高分辨率。 Time::Hires 是一个核心 Perl 库模块,应该包含在 Perl 中。

相关内容