在BASH中计算持续时间的优化方法

时间:2019-03-16 11:24:09

标签: python bash perl awk command-line

我正在使用我在BASH中编写的以下函数来计算持续时间,并确定持续时间是否超过5分钟,否则返回是,否则返回否。它正在按预期工作,但是我正在处理的文件很大(数百万行),并且需要很长时间才能完成工作。我正在寻找一些优化的方法来做到这一点。

datediff() {
d2=$(date -d "$2" +%s)
d1=$(date -d "$3" +%s)
secs=$((d1 - d2))
impacted="no"
if [ $(($secs / 300 )) -gt 0 ]
  then
  impacted="yes"
fi
printf "%s\n" "$impacted"
}

我正在while循环中调用此函数,该循环正在逐行读取输入文件。

while IFS=',' read -r line;
do
   IFS=',' read source almapear almclear <<< "$line"
   echo $line, $(datediff $source "$almapear" "$almclear")
done < "$1" | tee -a output_$1

下面是示例输入文件,其中包含源名称,警报出现时间和警报清除时间:

D00O0:SOURCE3,Mon Oct 01 16:02:35 AST 2018,Mon Oct 01 16:04:19 AST 2018
D00O0:SOURCE3,Mon Oct 08 08:53:17 AST 2018,Mon Oct 08 08:54:57 AST 2018
D00O1:SOURCE3,Mon Oct 15 09:25:14 AST 2018,Mon Oct 15 09:26:59 AST 2018
D00O1:SOURCE3,Mon Oct 15 16:56:58 AST 2018,Mon Oct 15 17:58:41 AST 2018
D00O1:SOURCE3,Mon Oct 22 08:56:48 AST 2018,Mon Oct 22 09:58:31 AST 2018
D00O1:SOURCE3,Sat Oct 06 09:17:42 AST 2018,Sat Oct 06 09:19:24 AST 2018
D00O1:SOURCE3,Sat Oct 13 09:11:05 AST 2018,Sat Oct 13 09:12:47 AST 2018
D00O1:SOURCE3,Sat Oct 20 09:51:40 AST 2018,Sat Oct 20 09:53:23 AST 2018
D00O0:SOURCE3,Sat Oct 27 09:15:32 AST 2018,Sat Oct 27 09:17:11 AST 2018
D00O0:SOURCE3,Sat Sep 29 10:05:58 AST 2018,Sat Sep 29 11:07:43 AST 2018
D00O0:SOURCE3,Sun Oct 14 08:48:57 AST 2018,Sun Oct 14 09:50:43 AST 2018
D00O0:SOURCE3,Sun Oct 14 16:04:19 AST 2018,Sun Oct 14 16:06:00 AST 2018
D00O0:SOURCE3,Sun Oct 21 06:17:34 AST 2018,Sun Oct 21 06:19:17 AST 2018
D00O0:SOURCE3,Sun Oct 21 16:15:18 AST 2018,Sun Oct 21 17:17:00 AST 2018
D00O0:SOURCE3,Sun Oct 28 09:39:09 AST 2018,Sun Oct 28 09:40:47 AST 2018

以下是必需的输出:

D00O0:SOURCE3,Mon Oct 01 16:02:35 AST 2018,Mon Oct 01 16:04:19 AST 2018,no
D00O0:SOURCE3,Mon Oct 08 08:53:17 AST 2018,Mon Oct 08 08:54:57 AST 2018,no
D00O1:SOURCE3,Mon Oct 15 09:25:14 AST 2018,Mon Oct 15 09:26:59 AST 2018,no
D00O1:SOURCE3,Mon Oct 15 16:56:58 AST 2018,Mon Oct 15 17:58:41 AST 2018,yes
D00O1:SOURCE3,Mon Oct 22 08:56:48 AST 2018,Mon Oct 22 09:58:31 AST 2018,yes
D00O1:SOURCE3,Sat Oct 06 09:17:42 AST 2018,Sat Oct 06 09:19:24 AST 2018,no
D00O1:SOURCE3,Sat Oct 13 09:11:05 AST 2018,Sat Oct 13 09:12:47 AST 2018,no
D00O1:SOURCE3,Sat Oct 20 09:51:40 AST 2018,Sat Oct 20 09:53:23 AST 2018,no
D00O0:SOURCE3,Sat Oct 27 09:15:32 AST 2018,Sat Oct 27 09:17:11 AST 2018,no
D00O0:SOURCE3,Sat Sep 29 10:05:58 AST 2018,Sat Sep 29 11:07:43 AST 2018,yes
D00O0:SOURCE3,Sun Oct 14 08:48:57 AST 2018,Sun Oct 14 09:50:43 AST 2018,yes
D00O0:SOURCE3,Sun Oct 14 16:04:19 AST 2018,Sun Oct 14 16:06:00 AST 2018,no
D00O0:SOURCE3,Sun Oct 21 06:17:34 AST 2018,Sun Oct 21 06:19:17 AST 2018,no
D00O0:SOURCE3,Sun Oct 21 16:15:18 AST 2018,Sun Oct 21 17:17:00 AST 2018,yes
D00O0:SOURCE3,Sun Oct 28 09:39:09 AST 2018,Sun Oct 28 09:40:47 AST 2018,no

2 个答案:

答案 0 :(得分:3)

使用GNU awk的时间函数,这将比shell循环快几个数量级:

'wa"t"er'

查找手册页,以查看其使用的时区与输入文件中指定的时区以及在必要时如何进行调整。

答案 1 :(得分:1)

假设:

  • “ AST”和“ ADT”是唯一可以遇到的两个时区。
  • “ AST”是指UTC-4。
  • “ ADT”是指UTC-3。
  • 该文件是CSV文件。

以下解决方案具有以下功能:

  • 它可以正确处理DST更改附近的事件。
  • 它可以正确解析CSV文件。
  • 它会正确生成CSV文件。

任何现有解决方案(包括您自己的解决方案)都不能声称具有前两个功能。

#!/usr/bin/perl

use strict;
use warnings;
use feature qw( state );

use DateTime::Format::Strptime qw( );
use Text::CSV_XS               qw( );

sub parse_dt_str {
   my ($dt_str) = @_;

   state $format = DateTime::Format::Strptime->new(
      pattern => "%a %b %d %H:%M:%S %z %Y",
      locale  => "en",
   );

   $dt_str =~ s/\b(AST|ADT)\b/ $1 eq "AST" ? "-0400" : "-0300" /e;
   return $format->parse_datetime($dt_str);
}

my $csv = Text::CSV_XS->new({ auto_diag => 2, binary => 1, quote_space => 0 });
while ( my $row = $csv->getline(\*ARGV) ) {
   my $dt1 = parse_dt_str($row->[1]);
   my $dt2 = parse_dt_str($row->[2]);
   if ($dt1 && $dt2) {
      $row->[3] = $dt2->epoch - $dt1->epoch > 5*60 ? "yes" : "no";
   } else {
      $row->[3] = "???";
   }

   $csv->say(\*STDOUT, $row);
}