Dividir arquivo de log por data

7

Eu tenho um arquivo de log com este formato de log:

###<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

Como faço para dividir esse arquivo de registro por data nos arquivos YYYY_MM_DD.log?

    
por tm4ig 19.09.2016 / 13:22

3 respostas

7

Uma solução perl , aproveitando o GNU date para converter as datas:

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

Explicação

  • -ne : leia o arquivo de entrada linha a linha (salvando cada linha como a variável especial $_ ) e aplique o script dado por -e a cada linha.
  • if(/^###<(.*)>/) : se a linha começar com ###< , capture tudo entre <> as $1 (é o que os parênteses fazem).
  • chomp($d= date -d \ "$ 1 \" +% Y_% m_% d ); : o comando date reformata a data. Por exemplo:

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

    O chomp remove a nova linha final do resultado de date , para que possamos usá-la mais tarde.

  • $name="$d.log" : salvamos o resultado do comando date mais .log como a variável $name .
  • open(my $fh,">>","$name"); : abra o arquivo $name como o identificador de arquivo $fh . Não se preocupe se você não souber o que é um manipulador de arquivos, isso significa apenas que print $fh "foo" imprimirá foo em $name .
  • print $fh $_; : imprime a linha atual no arquivo para o qual o identificador de arquivo $fh aponta. Então, imprima a linha no que quer que esteja atualmente salvo como $name .
por terdon 19.09.2016 / 14:15
6

Uma abordagem para resolver isso pode ser usar o awk. Por exemplo, este comando:

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

deve dividir o arquivo nos arquivos, usando os campos de data como nomes de arquivos

    
por user000001 19.09.2016 / 14:12
6

com 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

Forma legível:

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
  • /^#+<[^>]+>$/ corresponde às linhas que contêm datas, o bloco cercado por {} só será executado se a condição corresponder. Se houver correspondências, obteremos a data no formato desejado usando o comando date externo e salvando a saída na variável file e salvando o conteúdo da variável lines até o arquivo file (do bloco anterior), e, em seguida, instanciar a variável lines novamente com a linha

  • Para todas as outras linhas, concatenamos as linhas como variável lines

  • O último bloco é salvo colocando-se o bloco END

por heemayl 19.09.2016 / 14:14