다음 열이 포함된 거대한 텍스트 파일이 있습니다.
col1 col2 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
abc dec 10 20 30 40 50 60 70 80 90 11 12 13
내가 찾고 있는 출력은 FullYear라는 새 열에 모든 월을 추가하는 것입니다.
col1 col2 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec FullYear
abc dec 10 20 30 40 50 60 70 80 90 11 12 13 486
awk 명령을 사용해 보았지만 데이터의 정밀도가 매우 높습니다. 아래 명령은 잘못된 출력을 제공합니다.
awk -F ' ' {print $1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13" "$14" "$3+$4+$5+$6+$7+$8+$9+$10+$11+$12+$13+$14}' inputfile.txt > outputfile.txt
이를 위해서는 Perl 스크립트를 작성해야 합니다.
답변1
Perl에서는 코드 한 줄만으로 이 작업을 수행하는 것이 매우 쉽습니다.
perl -MList::Util=sum -anE 'if (1 == $.) { say join(q{ }, @F, q{FullYear}) } else { say join(q{ }, @F, sum(@F[2..13])) }' «YOUR-FILE»
설명하다:
-MList::Util=sum
List::Util 모듈을 로드하고 sum
함수를 가져옵니다. 이는 와 동일합니다 use List::Util qw(sum)
.
-n
Perl에게 입력 파일을 한 줄씩 처리하고 각 줄에 대한 스크립트를 실행하도록 지시합니다. (다음 옵션이 암시적으로 활성화되므로 실제로는 중복됩니다.) -a
자동 분할 모드를 켜면 @F
필드당 하나의 항목이 있는 배열이 생성됩니다. -E
즉, 현재 Perl 기능(이 경우 "말")을 사용하여 명령줄 인수로 스크립트를 제공한다는 의미입니다.
이러한 옵션에 대한 자세한 내용은 perlrun
맨페이지/podfile에서 확인할 수 있습니다.
그런 다음 공백이 추가되고 주석 설명이 추가된 스크립트는 다음과 같습니다.
if (1 == $.) { # $. is the line number. Line 1 is header line.
say join(' ', @F, q{FullYear}); # print out the heder + FullYear
}
else {
# print out rows + sum of columns 2..13. Remember Perl counts from 0 in arrays,
# so column 2 is the 3rd column (the number for January).
say join(' ', @F, sum(@F[2..13]));
}
참고: Perl에게 코드 한 줄(적어도 신뢰하는 코드 한 줄 - 신뢰할 수 없는 스크립트에는 안전하지 않음)을 이해하는 데 도움을 달라고 요청할 수 -MO=Deparse
있으며 다음과 같은 출력이 제공됩니다.
주문하다:
perl -MO=Deparse -MList::Util=sum -anE 'if (1 == $.) { say join(q{ }, @F, q{FullYear}) } else { say join(q{ }, @F, sum(@F[2..13])) }' t-file
산출:
use List::Util (split(/,/, 'sum', 0));
use feature 'current_sub', 'bitwise', 'evalbytes', 'fc', 'postderef_qq', 'say', 'state', 'switch', 'unicode_strings', 'unicode_eval';
LINE: while (defined($_ = readline ARGV)) {
our @F = split(' ', $_, 0);
if (1 == $.) {
say join(' ', @F, 'FullYear');
}
else {
say join(' ', @F, &sum(@F[2..13]));
}
}
-e syntax OK
List::Util
따라서 로드를 확인 하고 -n
한 줄씩 실행한 -a
다음 split
.
답변2
Math::BigFloat
"엄청난 정밀도"가 귀하 에게 적합 합니까?
perl -MMath::BigFloat -ape 'my $s=0; $s += new Math::BigFloat($_) for @F[2..$#F]; s/$/ $s/'
abc dec 7.5 8.5
abc dec 7.5 8.5 16
List::Util::sum
와 함께 사용할 수도 있지만 Math::BigFloat
이는 의미가 없습니다.
perl -MMath::BigFloat -MList::Util=sum -ape 's/$/" ".sum map new Math::BigFloat($_), @F[2..$#F]/e'
답변3
그렇지는 않지만 perl
다음과 같이 하면 효과가 있는 것 같습니다.
awk 'NR==1 {$(NF+1) = "FullYear"; print} NR>1 {subtotal=0; for(f=0;f<=NF; f++) {subtotal+=$f}; $(NF+1)=subtotal; printf( "%s %s %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f %5.10f\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15 ) }' inputfile
답변4
@derobert의 변형입니다.
perl -MList::Util=sum -nlE 'say "$_ ", sum((split)[2..13])||"FullYear"' input
또는 사용-a
perl -MList::Util=sum -nalE 'say "$_ ", sum(@F[2..13])||"FullYear"' input