我从各自的日志文件中获取文件中各种进程的执行时间。具有执行时间的文件看起来类似于以下(它可能有数百个条目)
1:00:01.11
2:2.20
1.02
第一行是hours:minutes:seconds
,第二行是minutes:seconds
,第三行是seconds
。
我想将所有条目总和到总执行时间。我怎样才能在bash中实现这一目标?如果不是bash,那么你可以提供一些其他脚本语言的例子来总结时间戳吗?
答案 0 :(得分:6)
最常见的完整perl
脚本:
use strict;
use warnings;
my $seconds = 0;
while (<DATA>) {
my @fields = reverse(split(/:/));
for my $i (0 .. $#fields) {
$seconds += $fields[$i] * 60 ** $i;
}
}
print "$seconds\n";
__DATA__
1:00:01.11
2:2.20
1.02
或者,几乎不可读的单行版本:
$ perl -F: -wane '@F = reverse(@F); $seconds += $F[$_] * 60 ** $_ for 0 .. $#F; END { print "$seconds\n" }' times.log
输出:
3724.33
在这两种情况下,我们都会拆分H:M:S分隔符:
上的每一行,然后反转数组,以便我们可以从右向左进行处理。为了获得以秒为单位的总时间,我们可以依靠一个巧妙的技巧,我们将每个字段乘以60的幂。
如果您希望结果采用H:M:S格式而不是原始秒,来自POSIX核心模块的strftime()
可以轻松实现:
use POSIX qw(strftime);
print strftime('%H:%M:%S', gmtime($seconds)), "\n";
输出:
01:02:04
答案 1 :(得分:2)
使用(POSIX兼容的) awk
解决方案补充Matt Jacob's elegant perl
solution :
awk -F: '{ n=0; for(i=NF; i>=1; --i) secs += $i * 60 ^ n++ } END { print secs }' file
使用示例输入,此输出(秒中所有时间跨度的总和):
3724.33
请参阅以下部分,了解如何将此值格式化为时间跨度,类似于输入(01:02:04.33
)。
<强>解释强>
-F:
按:
将输入行拆分为字段,以便生成的字段($1
,$2
,...)表示小时,分钟和秒组件。
n=0; for(i=NF; i>=1; --i) secs += $i * 60 ^ n++
以相反的顺序枚举字段(第一秒,然后是分钟,然后是小时,如果已定义; NF
是字段数)并将每个字段与适当的倍数相乘60,以秒为单位生成一个整数值,存储在变量secs
中,累计跨行。
END { print secs }
在处理完所有行后执行,只需以秒为单位打印累计值。
自定义输出格式:
awk -F: '
{ n=0; for(i=NF; i>=1; --i) secs += $i * 60 ^ n++ }
END {
hours = int(secs / 3600)
minutes = int((secs - hours * 3600) / 60)
secs = secs % 60
printf "%02d:%02d:%05.2f\n", hours, minutes, secs
}
' file
以上收益率(相当于3724.33
秒):
01:02:04.33
END { ... }
块将secs
中累积的总秒数分成小时,分钟和秒,并使用printf
以适当的组件格式输出结果。< / p>
date
和 GNU awk
(非标准)日期格式化函数等实用程序不能用于格式化输出的原因有两个:
标准时间格式说明符%H
在24小时内回绕,因此如果累计时间跨度超过24小时,则输出将不正确。
小数秒将丢失(Unix时间戳的粒度整秒)。