![将 stderr 重定向到文件并在每一行前面加上一个字符串](https://linux22.com/image/192952/%E5%B0%86%20stderr%20%E9%87%8D%E5%AE%9A%E5%90%91%E5%88%B0%E6%96%87%E4%BB%B6%E5%B9%B6%E5%9C%A8%E6%AF%8F%E4%B8%80%E8%A1%8C%E5%89%8D%E9%9D%A2%E5%8A%A0%E4%B8%8A%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2.png)
我想将命令 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-perl
debian 的包中。该软件包还包含Date::Parse
、Date::Language
和Time::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 中。