我有包含几行的文件。每个都有一个时间戳,后跟文本:
1534888050 some text
1534888051 some more text
1534888052 text
...并且想要将时间戳转换为可读格式,同时保留文本。结果应为:
Tue Aug 21 21:47:30 UTC 2018 some text
Tue Aug 21 21:47:31 UTC 2018 some more text
Tue Aug 21 21:47:32 UTC 2018 text
date -d@"${somedate}"
正确转换时间戳本身。
现在我想要通过一个过滤器/管道命令实现相同的效果sed或者awk(或任何其他常见命令)。
这不起作用,但大致解释了我的想法:
echo '1534888050 some text' | sed "s#^\([0-9]*\) .*#`date -d@\1`#g"
(这\1
是匹配的时间戳)
有什么方法可以优雅地实现这一点吗?
答案1
这日期工具软件包非常适合此类事情,特别是dconv
工具。 (当安装在 Ubuntu 系统上时,该命令可用作dateutils.dconv
。)
这是一个例子:
$ cat testfile.txt
1534888050 some text
1534888051 some more text
1534888052 text
$ dateutils.dconv -i '%s' -f '%a %b %d %T %Y' -S <testfile.txt
Tue Aug 21 21:47:30 2018 some text
Tue Aug 21 21:47:31 2018 some more text
Tue Aug 21 21:47:32 2018 text
$ dateutils.dconv -i '%s' -f '%F %T' -S <testfile.txt
2018-08-21 21:47:30 some text
2018-08-21 21:47:31 some more text
2018-08-21 21:47:32 text
$
旗帜-S
是关键;它告诉工具在“sed 模式”下运行并在输出中包含非日期文本。
该-i
标志指定输入日期格式,该-f
标志指定输出日期格式。
答案2
如果您有 GNU awk (又名gawk
),您可以使用其内置strftime
函数将纪元时间转换为您选择的格式:
$ TZ=UTC gawk '{$1 = strftime("%a %b %d %H:%M:%S %Z %Y", $1)} 1' file
Tue Aug 21 21:47:30 UTC 2018 some text
Tue Aug 21 21:47:31 UTC 2018 some more text
Tue Aug 21 21:47:32 UTC 2018 text
您还可以将 perl 与POSIX
模块一起使用:
$ TZ=UTC perl -MPOSIX -alne '
print join " ", strftime("%a %b %d %H:%M:%S %Z %Y", localtime shift @F), @F
' file
Tue Aug 21 21:47:30 UTC 2018 some text
Tue Aug 21 21:47:31 UTC 2018 some more text
Tue Aug 21 21:47:32 UTC 2018 text
尽管 GNU 实现sed
确实有一个e
允许执行外部命令的修饰符,但它在整个模式空间上运行 - 使得在实践中使用起来相当麻烦。
答案3
使用awk:
{
"date -d @" $1 | getline $1
}
1
结果:
Tue, Aug 21, 2018 4:47:30 PM some text
Tue, Aug 21, 2018 4:47:31 PM some more text
Tue, Aug 21, 2018 4:47:32 PM text
答案4
您需要意识到的是,GNU sed
用 的 RHS 中命令求值的结果替换整个模式空间s///e
。因此,为了适应这种行为,我们使用echo + date
命令组合,如下所示:
sed -e 's/^\([1-9][0-9]*\)\(.*\)/echo "`date -d@\"\1\"`\2"/e' input-file.txt
对于Perl
,很简单,LHS 上匹配的内容仅在 RHS 上被替换,正如人们直观地期望的那样:
perl -pe 's/(\d+)/qx(date -d@"$1") =~ s|\n||r/e' input-file.txt