我有一个巨大的文本文件,其中包含以下几列
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 功能(在本例中为“say”)提供一个脚本作为命令行参数。
这些选项的完整详细信息可以在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