awk/sed 쉘 스크립트 도움말

awk/sed 쉘 스크립트 도움말

아래 표의 정보(가짜정보)를 이용하여 스크립트를 작성해야 합니다.

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
  • mktimeEPOCH 형식의 문자열에서 타임스탬프(초 단위) 생성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 를 실행하여 다른 이름으로 저장을 반환하도록 요청합니다. 마지막으로 수정된 첫 번째 필드를 인쇄합니다.perlawk-F@F$F[0]=~s/IE...IE$F[1]=~s#...MM/DD/YYYYchomp(...dateMon YYYYchomp$d$d

관련 정보