In bash, it's fairly simple:
exec 2> >(perl -MDate::Format -pe 's/^/time2str("%Y-%m-%d %H:%M:%S%z [stderr] ",time)/e' > /var/log/some.log)
You can turn that perl one-liner into a standalone script:
#!/usr/bin/perl
use Date::Format;
while(<>) {
s/^/time2str("%Y-%m-%d %H:%M:%S%z [stderr] ",time)/e;
print;
}
Save that as, say, /usr/local/bin/timestamp-text
and make it executable with chmod +x /usr/local/bin/timestamp-text
. Then you can write the exec
as:
exec 2> >(/usr/local/bin/timestamp-text > /var/log/some.log)
In other Bourne-like shells, you can't use exec
to redirect to a process substitution, you have to use a fifo. I don't want to rewrite the same answer again, so I'll just point you to another answer I wrote for a similar question: https://unix.stackexchange.com/a/644862/7696
BTW, the timestamp-text
script (or the one-liner version) can be written in whatever language you like, as long as it has decent date formatting capabilities (most languages do). It will need to query the current time for every input line it modifies, not just at the time it was first run (otherwise, you could probably just use /bin/date
)
NOTE: the Date::Format module is in the libtimedate-perl
package on debian. This package also contains the Date::Parse
, Date::Language
, and Time::Zone
modules. It should be available as a package for most other distros too, otherwise install it with cpan
.
Update
I just remembered that a program called ts
exists to do exactly this kind of time-stamping, so there's no need to write your own perl or whatever script. It's available in the moreutils package.
exec 2> >(ts "%Y-%m-%d %H:%M:%S%z [stderr]" > /var/log/some.log)
It is, however, a perl
script itself and requires the Getopt::Long module to be installed, and (depending on which command line options you use) may also require Date::Parse
, Time::Duration, and/or Time::HiRes. Time::Hires is a core perl library module and should be included with perl.
exec
redirections and using a fifo to modify the output with sed before writing to a file (also, you'll want the exec to apply to stderr, not stdout, so useexec >&2
) – cas Jul 13 '21 at 05:35