web-dev-qa-db-fra.com

Diviser le fichier journal par date

J'ai un fichier journal avec ce format de journal:

###<Aug 8, 2016 11:59:05 PM>
different text
...
different text
###<Aug 15, 2016 9:10:55 AM>
different text
...
...
...
different text
###<Aug 22, 2016 10:02:17 PM>
different text
...
...
...
...
different text
###<Sep 1, 2016 1:00:01 AM>
different text
###<Sep 7, 2016 3:00:01 PM>
different text
...
...
different text

Comment diviser ce fichier journal par date en fichiers YYYY_MM_DD.log?

7
tm4ig

Une solution Perl, tirant parti de GNU date pour convertir les dates:

Perl -ne 'if(/^###<(.*)>/){
            chomp($d=`date -d \"$1\" +%Y_%m_%d`);
            $name="$d.log"
          } 
          open(my $fh,">>","$name"); 
          print $fh $_;' file.log 

Explication

  • -ne: lit ligne par ligne le fichier en entrée (en enregistrant chaque ligne comme variable spéciale $_) et applique le script donné par -e à chaque ligne.
  • if(/^###<(.*)>/): si la ligne commence par ###<, capturez tout ce qui se trouve entre <> comme $1 (c'est ce que font les parenthèses).
  • chomp($d=date -d\"$ 1 \" +% Y_% m_% d);: la commande date reformate la date. Par exemple:

    $ date -d "Sep 1, 2016 1:00:01 AM" +%Y_%m_%d
    2016_09_01
    

    La chomp supprime la nouvelle ligne finale du résultat de date afin que nous puissions l'utiliser ultérieurement.

  • $name="$d.log": nous enregistrons le résultat de la commande date plus .log sous la forme de la variable $name.
  • open(my $fh,">>","$name");: ouvre le fichier $name en tant que descripteur de fichier $fh. Ne vous inquiétez pas si vous ne savez pas ce qu'est un descripteur de fichier, cela signifie simplement que print $fh "foo" imprimera foo dans $name.
  • print $fh $_;: affiche la ligne en cours dans le fichier que le fichier gère. $fh pointe vers. Donc, imprimez la ligne dans tout ce qui est actuellement enregistré en tant que $name.
7
terdon

Une approche pour résoudre ce problème pourrait être d'utiliser awk. Par exemple, cette commande:

awk -F'[ <,]+' '/^###/{close(f);f=$4"_"$2"_"$3".log"}{print >> f}END{close(f)}' file

devrait scinder le fichier en fichiers, en utilisant les champs de date comme noms de fichier

6
user000001

Avec awk:

awk '/^#+<[^>]+>$/ {if (lines) print lines >file; \
     dt=gensub("^#+<([^>]+)>$", "\\1", $0)
     dt_cmd="date -d \""dt"\" +%Y_%m_%d.log" \
     dt_cmd | getline file; lines=$0; next}; \
     {lines=lines ORS $0} END {print lines >file}' file.log

Forme lisible:

awk '
      /^#+<[^>]+>$/ {
                    if (lines) 
                        print lines >file
                    dt=gensub("^#+<([^>]+)>$", "\\1", $0)
                    dt_cmd="date -d \""dt"\" +%Y_%m_%d.log"
                    dt_cmd | getline file; lines=$0
                    next
                    }
      {
      lines=lines ORS $0
      } 
      END {
          print lines >file
          }' file.log
  • /^#+<[^>]+>$/ correspond aux lignes contenant les dates. Le bloc entouré de {} ne sera exécuté que si la condition est la même. Si les correspondances, nous obtenons la date au format souhaité en utilisant la commande externe date, en enregistrant le résultat dans la variable file, et en enregistrant le contenu de la variable lines dans la mesure où le fichier file (à partir du bloc précédent), puis instanciez à nouveau la variable lines avec la ligne

  • Pour toutes les autres lignes, nous concaténons les lignes en tant que variable lines

  • Le dernier morceau est sauvegardé en mettant dans le bloc END

6
heemayl