Converter datas formatadas para segundos desde a época

6

Eu tenho um arquivo:

pablo tty8 Thu Nov 1 12:51:21 2012 still logged in 
(unknown tty8 Thu Nov 1 12:50:57 2012 - Thu Nov 1 12:51:21 2012 (00:00) 
pablo tty2 Thu Nov 1 12:50:39 2012 still logged in 
pablo tty7 Thu Nov 1 12:49:45 2012 - Thu Nov 1 12:50:56 2012 (00:01) 
(unknown tty7 Thu Nov 1 12:34:32 2012 - Thu Nov 1 12:49:45 2012 (00:15)

Eu quero substituir o arquivo na data acima por um segundo. Quero imprimir:

pablo tty8 1351770681 still logged in 
(unknown tty8 1351770657 - 1351770681 (00:00) 
pablo tty2 1351770639 still logged in 
pablo tty7 1351770585 - 1351770656 (00:01) 
(unknown tty7 1351769672 - 1351770585 (00:15)

Eu tentei este comando:

gawk --posix 'function my()
{"date -d 7"$0"7 +%s" | getline b; 
gsub( /[A-Za-z]{3} [A-Za-z]{3} [0-9] ([0-9]{2}:){2}[0-9]{2} [0-9]{4}/,b );print}
{ my() }' file

O comando acima não funciona:

$ gawk --posix 'function my()
> {"date -d 7"$0"7 +%s" | getline b; 
> gsub( /[A-Za-z]{3} [A-Za-z]{3} [0-9] ([0-9]{2}:){2}[0-9]{2} [0-9]{4}/,b ); print}
> { my() }' ta
date: błędna data: 'pablo tty8 Thu Nov 1 12:51:21 2012 still logged in '
pablo tty8  still logged in 
(unknown tty8 1351897200 - 1351897200 (00:00) 
date: błędna data: 'pablo tty2 Thu Nov 1 12:50:39 2012 still logged in '
pablo tty2 1351897200 still logged in 
date: błędna data: 'pablo tty7 Thu Nov 1 12:49:45 2012 - Thu Nov 1 12:50:56 2012 (00:01) '
pablo tty7 1351897200 - 1351897200 (00:01) 
(unknown tty7 1351897200 - 1351897200 (00:15)

Como melhorar o comando acima?

    
por nowy1 03.11.2012 / 13:17

5 respostas

6

Para fazer do seu jeito, isso teria que ser algo como:

POSIXLY_CORRECT=1 awk '
  {
    n = ""; r = $0
    while (match(r, /[[:alpha:]]{3} [[:alpha:]]{3} +[0-9]+ ([0-9]{2}:){2}[0-9]{2} [0-9]{4}/)) {
      c = "date -d\"" substr(r,RSTART,RLENGTH) "\" +%s"
      c | getline b
      close(c)
      n = n substr(r,1,RSTART-1) b
      r =  substr(r,RSTART+RLENGTH)
    }
    print n r
  }'
    
por 03.11.2012 / 23:51
6

Aqui está uma abordagem alternativa (usando mktime ):

#!/bin/awk -f
{
    split($6,A,":");
    S1=sprintf("%d %d %d %d %d %d",$7,$4,$5,A[1],A[2],A[3])
    T1=mktime(S1)
    if ($8=="-") {
        split($12,A,":");
        S2=sprintf("%d %d %d %d %d %d",$13,$10,$11,A[1],A[2],A[3])
        T2=mktime(S2)
        print $1,$2,T1,$8,T2,$14
    }
    else {
        print $1,$2,T1,$8,$9,$10
    }
}
    
por 03.11.2012 / 15:22
4

Você pode fazer assim com o GNU sed:

convert_date.sed

: a
s/(([A-Za-z]{3} ){2}[0-9]{1,2} ([0-9]{2}:){2}[0-9]{2} [0-9]{4})(.*)/\n\n/
h
s/.*\n//
s/^/date -d "/
s/$/" +%s/e
G
s/([^\n]+)\n([^\n]+)\n([^\n]+)\n.*//
/([A-Za-z]{3} ){2}[0-9]{1,2} ([0-9]{2}:){2}[0-9]{2} [0-9]{4}/ta

Execute assim:

sed -rf convert_date.sed infile

Saída:

pablo tty8 1351770681 still logged in 
(unknown tty8 1351770657 - 1351770681 (00:00) 
pablo tty2 1351770639 still logged in 
pablo tty7 1351770585 - 1351770656 (00:01) 
(unknown tty7 1351769672 - 1351770585 (00:15)

Explicação

Isso pode parecer um pouco assustador no começo, mas a ideia não é tão complicada. Essa expressão regular, ([A-Za-z]{3} ){2}[0-9]{1,2} ([0-9]{2}:){2}[0-9]{2} [0-9]{4} , que ocorre na primeira substituição e a condicional no final, corresponde ao tipo de data usado na entrada, captura e isola a data. Os bits ao redor são armazenados no espaço de espera enquanto date -d é executado na data capturada. Finalmente, todos os bits são coletados no espaço padrão e reorganizados na ordem correta.

A condicional no final repete o processo se alguma data permanecer no espaço padrão.

    
por 03.11.2012 / 20:15
4

Com perl e seu módulo Date::Manip :

perl -MDate::Manip -pe '
  s/\w{3} \w{3} +\d+ \d\d:\d\d:\d\d \d+/
  UnixDate ParseDate("$&"),"%s"/ge'
    
por 03.11.2012 / 22:03
2

A solução Perl fornecida por Stephane requer um módulo Perl não núcleo. Pode-se usar o módulo central (desde 5.10), Time :: Piece , da mesma forma:

#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $t = Time::Piece->new;
while (<>) {
    s{\w{3}\s(\w{3}\s\d{1,2}\s\d\d:\d\d:\d\d\s\d{4})}
        {$t=Time::Piece->strptime($1,"%b %d %H:%M:%S %Y");
        sprintf "%s",$t->epoch}ge;
    print;
}
    
por 04.11.2012 / 17:23

Tags