次の列を含む巨大なテキストファイルがあります。
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では、1行のコードでこれを行うのはとても簡単です。
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に入力ファイルを1行ずつ処理し、各行に対してスクリプトを実行するように指示します。 (次のオプションが暗黙的に有効になるため、実際には重複します。)-a
自動分割モードをオンにすると、@F
フィールドごとに1つの項目を持つ配列が作成されます。-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に、1行のコード(少なくとも信頼できる1行のコード - 信頼できないスクリプトでは安全ではありません)を理解するのに役立つように依頼することができます。次のような-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
1行ずつ実行して-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