1

これを私が25年前に知っていて忘れていたことにまでチョークで書いてください....

私は Windows イベント ログからのログ出力を持っていますが、タイムスタンプ形式を制御することはできません (もしそうなら、YYYYMMDD HH24MMSS のような適切なものを選択して、文字列として扱われるときに簡単に並べ替えられるようにします。
簡単な方法があると確信しています。 sedまたは何らかのソートパラメータを使用してこれを行う方法誰かがこれに対する簡単な解決策を持っていますか?

サンプルデータ:

SERVER01,1/1/2013 12:00:01 AM,8,FOO,TOO
SERVER01,4/10/2012 4:43:06 PM,8,FOO,TOO
SERVER01,4/11/2012 4:43:06 PM,8,FOO,TOO
SERVER01,4/9/2012 4:43:06 PM,8,FOO,TOO
SERVER02,12/31/2012 11:59:59 PM,8,FOO,TOO
SERVER02,4/10/2012 4:43:06 PM,8,FOO,TOO
SERVER02,4/9/2012 4:43:06 PM,8,FOO,TOO

ご希望の順番:

SERVER01,4/9/2012 4:43:06 PM,8,FOO,TOO
SERVER02,4/9/2012 4:43:06 PM,8,FOO,TOO
SERVER01,4/10/2012 4:43:06 PM,8,FOO,TOO
SERVER02,4/10/2012 4:43:06 PM,8,FOO,TOO
SERVER01,4/11/2012 4:43:06 PM,8,FOO,TOO
SERVER02,12/31/2012 11:59:59 PM,8,FOO,TOO
SERVER01,1/1/2013 12:00:01 AM,8,FOO,TOO

タイムスタンプの再フォーマットは問題ありません。方法がわかりません。これは Windows で実行する必要があり、Cygwin を利用できます (この同じファイルの grep フィルタリングに既に使用しています)。

4

5 に答える 5

2

Awkには間違いなくcygwinが付属しており、日付を並べ替え可能な形式に並べ替えることができます(awkの初心者はやめたので、これは醜いですが、うまくいきます)。このスクリプトにログインしてから、単純な並べ替えにログインします

#! /bin/awk -f
BEGIN {
   FS=",";
}
{
   linedate=$2;
   split(linedate,datetime," ");
   split(datetime[1],datepieces,"/");
   date=sprintf( "%d/%02d/%02d", datepieces[3], datepieces[1], datepieces[2]);
   split(datetime[2],timepieces,":");
   time=sprintf( "%02d:%02d:%02d", timepieces[1], timepieces[2], timepieces[3] );
   print date " " time " " datetime[3] "," $1 "," $3 "," $4 "," $5;
}
于 2012-05-07T20:33:51.037 に答える
2

以下は、ソート可能なタイムスタンプを各行の先頭に追加する Perl スクリプトです。

#!/usr/bin/perl

use strict;
use warnings;

while (<>) {
    my $timestamp = (split /,/)[1];
    my($mon, $mday, $year, $hour, $min, $sec, $ampm) =
        $timestamp =~ m{^(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)\s+(AM|PM)};
    die "Can't parse timestamp on line $.\n" if not defined $ampm;
    if ($ampm eq 'AM') {
        $hour = 0 if $hour == 12;
    }
    else {
        $hour += 12 if $hour != 12;
    }

    printf "%04d-%02d-%02d %02d:%02d:%02d,%s",
           $year, $mday, $mon, $hour, $min, $sec, $_;
}

サンプル データの場合、次の出力が生成されます。

2013-01-01 00:00:01,SERVER01,1/1/2013 12:00:01 AM,8,FOO,TOO
2012-10-04 16:43:06,SERVER01,4/10/2012 4:43:06 PM,8,FOO,TOO
2012-11-04 16:43:06,SERVER01,4/11/2012 4:43:06 PM,8,FOO,TOO
2012-09-04 16:43:06,SERVER01,4/9/2012 4:43:06 PM,8,FOO,TOO
2012-31-12 23:59:59,SERVER02,12/31/2012 11:59:59 PM,8,FOO,TOO
2012-10-04 16:43:06,SERVER02,4/10/2012 4:43:06 PM,8,FOO,TOO
2012-09-04 16:43:06,SERVER02,4/9/2012 4:43:06 PM,8,FOO,TOO

foo.plサンプル データを日付順に並べ替えるには、上記の Perl スクリプトを次のように仮定します。

./foo.pl in.txt | sort | sed 's/^[^,]*,//'

これにより、質問で指定された出力と同じ出力が生成されます。

必要に応じて、Perl スクリプトを微調整することで、ファイル全体をメモリに格納、変更、および並べ替えるという犠牲を払って、 sortandコマンドを回避できます。これは、非常に大きな入力の場合に問題になる可能性があります。sed

#!/usr/bin/perl

use strict;
use warnings;

my @lines = ();

while (<>) {
    my $timestamp = (split /,/)[1];
    my($mon, $mday, $year, $hour, $min, $sec, $ampm) =
        $timestamp =~ m{^(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)\s+(AM|PM)};
    die "Can't parse timestamp on line $.\n" if not defined $ampm;
    if ($ampm eq 'AM') {
        $hour = 0 if $hour == 12;
    }
    else {
        $hour += 12 if $hour != 12;
    }

    push @lines, sprintf "%04d-%02d-%02d %02d:%02d:%02d,%s",
                         $year, $mday, $mon, $hour, $min, $sec, $_;
}

@lines = sort @lines;
foreach (@lines) {
    s/^[^,]*,//;
}
print @lines;
于 2012-05-03T08:36:51.617 に答える
1

クリス、

提供されている以下のコードを試してみる必要があるかもしれません。具体的には、sortコマンドを見てください。

私が作成したawkスクリプトは、Windows Server 2003の「タイムスタンプ」をサニタイズして、1桁の数字にゼロが事前に埋め込まれるようにします。結果の正常なタイムスタンプの形式を変更するのは非常に簡単です。

デフォルトのcygwinインストールで動作するはずです。

ご意見をお聞かせください。フィードバックに基づいて、調整が必要になる場合があります。

ロブ

$ gawk -f foo.awk event_log.txt | sort  -n -k2
SERVER01,04/09/2012 04:43:06 PM,8,FOO,TOO
SERVER01,04/10/2012 04:43:06 PM,8,FOO,TOO
SERVER01,04/11/2012 04:43:06 PM,8,FOO,TOO
SERVER02,04/09/2012 04:43:06 PM,8,FOO,TOO
SERVER02,04/10/2012 04:43:06 PM,8,FOO,TOO
SERVER02,12/31/2012 11:59:59 PM,8,FOO,TOO
SERVER01,01/01/2013 12:00:01 AM,8,FOO,TOO

foo.awkはどこにありますか

BEGIN { FS = "," }
{ print $1"," prepadDate($2) "," $3 "," $4 "," $5 }

#
# Returnes a useful timestamp given the timestamp received in event logs on Windows Server 2003
#
function prepadDate(winSrvr2003ts) {

        padded_day = ""
        padded_month = ""
        year = ""

        padded_date = ""
        split(winSrvr2003ts,numbers," ")

        split(numbers[1], date, "/")
        split(numbers[2], time, ":")
        antePostMeridian = numbers[3]

        padded_day = prePadAZero(date[1])
        padded_month = prePadAZero(date[2])
        year = date[3]
        padded_hour = prePadAZero(time[1])
        minute = time[2]
        seconds = time[3]

        #
        # Alter the return statememnt to format the timestamp according to your needs
        # rememebering that string concatenation in gawk is simply a space.
        #
        return padded_day "/" padded_month "/" year " " padded_hour ":" minute ":" seconds " " antePostMeridian
}

#
# Prepend a zero to number if it is a single digit
#
function prePadAZero(number){

        if (length(number) == 1)
                padded = "0" number
        else
                padded = number

        return padded
}
于 2012-05-08T19:12:42.407 に答える
1

私はこのようなことをしなければなりませんでした-マージする必要があるlog4jタイムスタンプを持つ複数のログファイルがありました。

私が解決した解決策はgawk、タイムスタンプをエポックからのミリ秒に変換し、すべての行にプレフィックスを付けることでした。その後の使用sortは簡単でした。

上記の形式に変換したのは、t9imestamp 値に対していくつかの演算も実行したかったからです。yymmddXhhmmss近道をしてin に変換できるかもしれませんsedXはforおよびforにam/pm使用するためのものです0am1pm

さらに考えてみると、 を使用して を使用gawkした方がよいでしょう。sedprintf

于 2012-04-30T17:59:30.650 に答える
1

このUNIXコマンドを試してみてください。

タイムスタンプの部分だけやってます。

入力

1/1/2013 12:00:01 AM
4/10/2012 4:43:06 PM
4/9/2012 4:43:06 PM
12/31/2012 11:59:59 PM
4/10/2012 4:43:06 PM
4/9/2012 4:43:06 PM

Unix コマンド

$>sort -t "/"  -k 1.8,1.4 Input| sort -t ":" -r -k 1 -k 2.1,2.2 -k 3.1,3.2 | sort -t " " -r -k 3.1

出力

4/9/2012 4:43:06 PM
4/9/2012 4:43:06 PM
4/10/2012 4:43:06 PM
4/10/2012 4:43:06 PM
12/31/2012 11:59:59 PM
1/1/2013 12:00:01 AM

必要に応じてスクリプトを変更できます。

于 2012-05-08T11:35:14.483 に答える