J'utilise la fonction ci-dessous que j'ai écrite en BASH pour calculer la durée et décider si la durée est supérieure à 5 minutes, elle renvoie oui, sinon non. Il fonctionne comme prévu, mais les fichiers que je traite sont énormes (des millions de lignes) et cela prend très longtemps pour terminer le travail. Je cherche un moyen optimisé de le faire.

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"
}

J'appelle cette fonction dans une boucle while qui lit le fichier d'entrée ligne par ligne.

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

Voici un exemple de fichier d'entrée, qui contient le nom de la source, l'heure d'apparition de l'alarme, puis l'heure d'effacement de l'alarme:

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

Voici la sortie requise:

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
1
Ibraheem 16 mars 2019 à 14:24

2 réponses

Meilleure réponse

Avec GNU awk pour les fonctions temporelles, ce sera des ordres de grandeur plus rapides que votre boucle shell:

$ cat tst.awk
BEGIN {
    FS = "[, :]"
    OFS = ","

    split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",tmp)
    for (i in tmp) {
        mth[tmp[i]] = i
    }
    maxSecs = 5 * 60
}
{
    begSecs = mktime($10" "mth[$4]" "$5" "$6" "$7" "$8)
    endSecs = mktime($18" "mth[$12]" "$13" "$14" "$15" "$16)
    print $0, ( (endSecs - begSecs) > maxSecs ? "yes" : "no" )
}

$ awk -f tst.awk file
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

Consultez la page de manuel pour voir quel fuseau horaire il utilise par rapport au fuseau horaire spécifié dans votre fichier d'entrée et comment l'ajuster si nécessaire.

3
Ed Morton 16 mars 2019 à 16:15

Hypothèses:

  • "AST" et "ADT" sont les deux seuls fuseaux horaires qui peuvent être rencontrés.
  • "AST" fait référence à UTC-4.
  • "ADT" fait référence à UTC-3.
  • Le fichier est un fichier CSV.

La solution ci-dessous présente les fonctionnalités suivantes:

  • Il gère correctement les événements à proximité des modifications DST.
  • Il analyse correctement un fichier CSV.
  • Il génère correctement un fichier CSV.

Aucune des solutions existantes (y compris la vôtre) ne peut prétendre avoir les deux premières fonctionnalités.

#!/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);
}
1
ikegami 16 mars 2019 à 15:29