bash的总和持续时间

时间:2017-02-20 20:58:46

标签: bash perl awk

我从各自的日志文件中获取文件中各种进程的执行时间。具有执行时间的文件看起来类似于以下(它可能有数百个条目)

1:00:01.11
2:2.20
1.02

第一行是hours:minutes:seconds,第二行是minutes:seconds,第三行是seconds

我想将所有条目总和到总执行时间。我怎样才能在bash中实现这一目标?如果不是bash,那么你可以提供一些其他脚本语言的例子来总结时间戳吗?

2 个答案:

答案 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小时,则输出将不正确。

    < / LI>
  • 小数秒将丢失(Unix时间戳的粒度整秒)。