Преобразуйте отформатированные даты в секунды с эпохи

В ударе или ksh, помещенном имена файлов в массив, и, выполняют итерации по тому массиву в обратном порядке.

files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
  bar "${files[$i]}"
done

Код выше также работает в zsh если ksh_arrays опция установлена (это находится в ksh режиме эмуляции). В zsh существует более простой метод, который должен инвертировать порядок соответствий через спецификатор шарика:

for f in /var/logs/foo*.log(On); do bar $f; done

POSIX не включает массивы, поэтому если Вы хотите быть портативными, Ваша единственная опция непосредственно сохранить массив строк является позиционными параметрами.

set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
  eval "f=\${$i}"
  bar "$f"
  i=$((i-1))
done
6
04.11.2012, 01:38
5 ответов

Чтобы сделать это Ваш путь, который должен был бы быть чем-то как:

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
  }'
5
27.01.2020, 20:20

Вот альтернативный подход (использование 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
    }
}
5
27.01.2020, 20:20

Вы могли сделать это как это с 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\4\n\1/
h
s/.*\n//
s/^/date -d "/
s/$/" +%s/e
G
s/([^\n]+)\n([^\n]+)\n([^\n]+)\n.*/\2\1\3/
/([A-Za-z]{3} ){2}[0-9]{1,2} ([0-9]{2}:){2}[0-9]{2} [0-9]{4}/ta

Выполните его как это:

sed -rf convert_date.sed infile

Вывод:

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)

Объяснение

Это может выглядеть немного пугающим сначала, но идея не сложный. Это регулярное выражение, ([A-Za-z]{3} ){2}[0-9]{1,2} ([0-9]{2}:){2}[0-9]{2} [0-9]{4}, то, которое происходит в первой замене и условном выражении в конце, соответствует типу даты, используемому во входе, это получает и изолирует дату. Окружающие биты хранятся в пространстве хранения в то время как date -d выполняется в полученную дату. Наконец, все биты собраны в пространстве шаблона и реорганизованы в правильный порядок.

Условное выражение в конце повторяет процесс, если какие-либо даты остаются в пространстве шаблона.

4
27.01.2020, 20:20
  • 1
    Спасибо за хорошее решение. У меня просто есть вопрос. Ваше решение, может также использоваться в awk? –  nowy1 03.11.2012, 21:30
  • 2
    @nowy1: Не легко нет. Несколько полезных awk решений были предложены, возможно, они сделают. –  Thor 04.11.2012, 01:09

С perl и Date::Manip модуль:

perl -MDate::Manip -pe '
  s/\w{3} \w{3} +\d+ \d\d:\d\d:\d\d \d+/
  UnixDate ParseDate("$&"),"%s"/ge'
4
27.01.2020, 20:20

Решение для Perl, предоставленное Stephane, требует неосновного модуля Perl. Можно было использовать базовый модуль (начиная с 5.10), Время:: Часть, так же:

#!/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;
}
2
27.01.2020, 20:20

Теги

Похожие вопросы