我必须使用下表中的信息制作一个脚本(假信息)
AnimalNumber,DOB,Gender,Breed,Date-moved-in
IE161289240602,04/02/2010,M,AAX,20/07/2011,
IE141424490333,13/01/2009,M,LMX,21/09/2010,
IE151424420395,19/01/2007,F,LMX,20/08/2010,
基本上我只需要列出出生日期,animalnumber
但动物编号应该像这样分解
IE161289240602
应该1612892 4 0602
而且只应该列出出生的月份和年份,所以第一行是这样的
Feb 2010 1412892 4 0602
关于如何做到这一点有什么想法吗?恐怕这有点超出我的技能范围
答案1
为了GNU awk
awk -F, '
NR>1{
sub("..","") #remove first two letters (mean IE)
d=""
for(i=split($2,D,"/");i>0;i--) #format 2nd field into `YY MM DD`
d=d D[i] " "
print strftime("%b %Y",mktime(d 0" "0" "0)),gensub("[0-9]"," & ",8,$1)
}' file
mktime
从 EPOCH 格式的字符串生成时间戳(以秒为单位)YYYY MM DD HH MM SS
strftime
将时间戳转换为所需的格式(在情况下%b %Y
)gensub
用尾随空格替换第一个字段 ( ) 中的8
数字 ( )本身 ( )[0-9]
$1
&
我们只看到字符串格式,因此可以使用sed:
sed -r '
1d
s/./ & /10
s|(../)(../)|\2\1|
s/..([^,]*),([^,]*).*/date -d "\2" +"%b %Y \1"/e
' file
或为了sed没有e命令
sed '
1d
s/./ & /10
s|\(../\)\(../\)|\2\1|
s/..\([^,]*\),\([^,]*\).*/date -d "\2" +"%b %Y \1"/
' file | bash
或者
sed '
s/./ & /10
s/../+"%b %Y /
s/,/" -d /
s|\(../\)\(../\)|\2\1|
s/,/\n/
1!P
d' file | xargs -n3 date
答案2
我会想“使用 perl”:
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
#get the column names out of the file. We remove the trailing linefeed.
#<> is the magic input file handle, so it reads from STDIN or files
#specified on command line, e.g. myscript.pl file_to_process.csv
my @headers = split ( /,/, <> =~ s/\n//r );
while ( <> ) {
chomp; #strip linefeed.
my %stuff;
#this makes use of the fact we know the headers already
#so we can map from the line into named columns.
@stuff{@headers} = split /,/; #read comma sep into hash
#DOB:
#take date, parse it into a unix time, then use strftime to output "Mon year"
print Time::Piece -> strptime ( $stuff{'DOB'}, "%d/%m/%Y" ) -> strftime("%b %Y");
#regex match against AnimalNumber, and then join it with space separation.
print "\t"; #separator
print join ( " ", $stuff{'AnimalNumber'} =~ m/(\d+)(\d)(\d{4})/ );
print "\n";
}
这输出:
Feb 2010 1612892 4 0602
Jan 2009 1414244 9 0333
Jan 2007 1514244 2 0395
这是通过以下方式实现的:
- 读取
<>
神奇文件句柄 - 从管道或文件名获取输入。 - 我们读取第一行,并将其转换为
@headers
. - 我们迭代每个附加行,并将逗号分隔的值映射到哈希(称为
%stuff
)。 - 提取
DOB
自%stuff
- 并根据需要将其处理strptime/strftime
为日期。 - 提取
AnimalNumber
并%stuff
使用正则表达式模式来提取您想要的数字 - 因为我们使用多个捕获组,所以捕获的元素将作为列表返回,然后我们可以使用将其粘在一起(使用空格分隔符)
join
。
编辑:因为您正在考虑排序 - 您必须首先将整个数据读入内存(出于效率原因,上面没有这样做)。
然而:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use Time::Piece;
my @headers = split( /,/, <> =~ s/\n//r );
my @records;
while (<>) {
chomp; #strip linefeed.
my %stuff;
#this makes use of the fact we know the headers already
#so we can map from the line into named columns.
@stuff{@headers} = split /,/; #read comma sep into hash
#DOB:
#take date, parse it into a unix time, then use strftime to output "Mon year"
$stuff{'formtime'} =
Time::Piece->strptime( $stuff{'DOB'}, "%d/%m/%Y" )->strftime("%b %Y");
#regex match against AnimalNumber, and then join it with space separation.
#separator
$stuff{'number_arr'} = [ $stuff{'AnimalNumber'} =~ m/(\d+)(\d)(\d{4})/ ];
push( @records, \%stuff );
}
foreach
my $record ( sort { $b->{'number_arr'}->[2] <=> $a->{'number_arr'}->[2] }
@records )
{
print join( "\t",
$record->{'formtime'}, join( " ", @{ $record->{'number_arr'} } ),
),
"\n";
}
与上面类似,但我们将每条记录预处理为哈希数组,然后sort
在打印之前使用输出 - 基于“key”字段 - 中的最后一组 4 位数字number_arr
。
答案3
另一种 Perl 方式,使用 GNU date
:
$ perl -F, -lane 'next if $.==1; $F[0]=~s/IE(\d{7})(\d)(\d{4})/$1 $2 $3/;
$F[1]=~s#(..).(..).(.*)#$2/$1/$3#;
chomp($d=`date -d "$F[1]" +"%b %Y"`);
print "$d $F[0]"' file
Feb 2010 1612892 4 0602
Jan 2009 1414244 9 0333
Jan 2007 1514244 2 0395
make-a
的perl
作用类似于awk
根据 给出的字符分割其输入行-F
并将其保存为数组@F
。$F[0]=~s/IE...
从第一个字段中删除并IE
根据要求拆分其余字段。会将$F[1]=~s#...
日期重新格式化为MM/DD/YYYY
.将chomp(...
运行 GNU ,要求date
它返回保存为.最后,打印修改后的第一个字段。Mon YYYY
chomp
$d
$d