bash的总和持续时间

zat*_*tka 3 bash perl awk

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

1:00:01.11
2:2.20
1.02
Run Code Online (Sandbox Code Playgroud)

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

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

Mat*_*cob 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
Run Code Online (Sandbox Code Playgroud)

或者,几乎不可读的单行版本:

$ perl -F: -wane '@F = reverse(@F); $seconds += $F[$_] * 60 ** $_ for 0 .. $#F; END { print "$seconds\n" }' times.log
Run Code Online (Sandbox Code Playgroud)

输出:

3724.33
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,我们在H:M:S分隔符上拆分每一行:,然后反转数组,以便我们可以从右到左进行处理.为了获得以秒为单位的总时间,我们可以依靠一个巧妙的技巧,我们将每个字段乘以60的幂.

如果您希望结果采用H:M:S格式而不是原始秒数,那么strftime()从POSIX核心模块可以轻松实现:

use POSIX qw(strftime);
print strftime('%H:%M:%S', gmtime($seconds)), "\n";
Run Code Online (Sandbox Code Playgroud)

输出:

01:02:04
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 6

用(符合 POSIX 标准的)解决方案补充Matt Jacob 的优雅perl解决awk方案

awk -F: '{ n=0; for(i=NF; i>=1; --i) secs += $i * 60 ^ n++ } END { print secs }' file
Run Code Online (Sandbox Code Playgroud)

使用样本输入,输出(所有时间跨度的总和,以秒为单位):

3724.33
Run Code Online (Sandbox Code Playgroud)

请参阅下面的部分,了解如何将此值格式化为时间跨度,类似于输入 ( 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
Run Code Online (Sandbox Code Playgroud)

以上产量(相当于3724.33秒):

01:02:04.33
Run Code Online (Sandbox Code Playgroud)

END { ... }块将累积的总秒数拆分secs为小时、分钟和秒,并使用printf.

不能使用dateGNU awk的(非标准)日期格式化函数等实用程序来格式化输出的原因有两个:

  • 标准时间格式说明符%H 环绕在 24 小时,因此如果累积时间跨度超过 24 小时,输出将不正确。

  • 小数秒会丢失(Unix 时间戳的粒度是 整秒)。