
以下の表の情報(偽情報)を使用してスクリプトを作成する必要があります。
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いいえ金利注文する
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
私は「パールを使用」したいと思います:
#!/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
から、印刷する前に「キー」フィールドに基づいて出力の最後の4桁のセットを使用してくださいnumber_arr
。
答え3
GNUを使用する別のPerl方式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
行います。最初のフィールドから削除し、必要に応じて残りのフィールドを分割します。は日付形式を再指定し、GNUを実行して別の名前で保存を返すように要求します。最後に変更された最初のフィールドを印刷します。perl
awk
-F
@F
$F[0]=~s/IE...
IE
$F[1]=~s#...
MM/DD/YYYY
chomp(...
date
Mon YYYY
chomp
$d
$d