Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unix Cygwin按日期对文本排序_Unix_Sorting_Cygwin_Timestamp - Fatal编程技术网

Unix Cygwin按日期对文本排序

Unix Cygwin按日期对文本排序,unix,sorting,cygwin,timestamp,Unix,Sorting,Cygwin,Timestamp,把这些记在我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

把这些记在我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过滤)。

我必须这样做——我有多个带有log4j时间戳的日志文件需要合并

我决定的解决方案是使用
gawk
将时间戳从epoch转换为毫秒,并在所有行前面加上前缀

我转换成上面的格式是因为我还想对t9imestamp值进行一些运算。您可以选择一个快捷方式,在
sed
中转换成
yymmddXhhmmss
X
用于
am/pm
使用
0
用于
am
1
用于
pm


进一步考虑,您也最好使用
gawk
,而不是
sed
,这样您就可以使用
printf
获得零填充数字。

我必须这样做——我有多个带有log4j时间戳的日志文件需要合并

我决定的解决方案是使用
gawk
将时间戳从epoch转换为毫秒,并在所有行前面加上前缀

我转换成上面的格式是因为我还想对t9imestamp值进行一些运算。您可以选择一个快捷方式,在
sed
中转换成
yymmddXhhmmss
X
用于
am/pm
使用
0
用于
am
1
用于
pm


进一步考虑,您也最好使用
gawk
,而不是
sed
,这样您就可以使用
printf
获得零填充数字。

下面是一个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, $_;
}
假设上面的Perl脚本是
foo.pl
,则按日期对示例数据进行排序:

./foo.pl in.txt | sort | sed 's/^[^,]*,//'
这将生成与问题中指定的输出相同的输出

如果愿意,对Perl脚本进行一个小小的调整,可以避免使用
sort
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;
!/usr/bin/perl
严格使用;
使用警告;
我的@lines=();
而(){
我的$timestamp=(拆分/,/)[1];
我的($mon、$mday、$year、$hour、$min、$sec、$ampm)=
$timestamp=~m{^(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)\s+(AM | PM)};
die“无法分析第$行的时间戳。\n”如果未定义$ampm;
如果($ampm相等于'AM'){
如果$hour==12,则$hour=0;
}
否则{
如果$hour!=12,则$hour+=12;
}
推送@lines,sprintf“%04d-%02d-%02d%02d:%02d:%02d%s”,
$year、$mday、$mon、$hour、$min、$sec、$\;
}
@行=排序@行;
foreach(@行){
s/^[^,]*,/;
}
打印@行;

下面是一个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, $_;
}
假设上面的Perl脚本是
foo.pl
,则按日期对示例数据进行排序:

./foo.pl in.txt | sort | sed 's/^[^,]*,//'
这将生成与问题中指定的输出相同的输出

如果愿意,对Perl脚本进行一个小小的调整,可以避免使用
sort
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;
!/usr/bin/perl
严格使用;
使用警告;
我的@lines=();
而(){
我的$timestamp=(拆分/,/)[1];
我的($mon、$mday、$year、$hour、$min、$sec、$ampm)=
$timestamp=~m{^(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+)\s+(AM | PM)};
die“无法分析第$行的时间戳。\n”如果未定义$ampm;
如果($ampm相等于'AM'){
如果$hour==12,则$hour=0;
}
否则{
如果$hour!=12,则$hour+=12;
}
推送@lines,sprintf“%04d-%02d-%02d%02d:%02d:%02d%s”,
$year、$mday、$mon、$hour、$min、$sec、$\;
}
@行=排序@行;
foreach(@行){
s/^[^,]*,/;
}
打印@行;

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;
}

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;
}

试试这个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

您可以根据需要修改脚本。

试试这个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
您可以根据需要修改脚本。

Chris

您可能需要使用下面提供的代码,特别是看看sort命令

我编写的awk脚本对Windows Server 2003“时间戳”进行了清理,以便用零预先填充单个数字。更改生成的sane时间戳的格式非常容易

应使用默认的cygwin安装

让我知道你的想法,可能需要这样做