Unix Cygwin按日期对文本排序
把这些记在我25年前知道的事情上,然后忘了 我有Windows事件日志的日志输出,无法控制时间戳格式(如果有,我会选择像YYYYMMDD HH24MMSS这样合理的格式,以便将其作为字符串进行排序。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
我相信有一种简单的方法可以通过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安装
让我知道你的想法,可能需要这样做