所以我在一个结构相同的目录中有各种.csv文件,第一行作为标题,第一列作为标签。假设文件1如下:
name,value1,value2,value3,value4,......
name1,100,200,0,0,...
name2,101,201,0,0,...
name3,102,202,0,0,...
name4,103,203,0,0,...
....
文件2:
name,value1,value2,value3,value4,......
name1,1000,2000,0,0,...
name2,1001,2001,0,0,...
name3,1002,2002,0,0,...
name4,1003,2003,0,0,...
....
所有.csv文件都具有相同的结构,具有相同的行数和列数。
我想要的是这样的东西:
name,value1,value2,value3,value4,......
name1,1100,2200,0,0,...
name2,1102,2202,0,0,...
name3,1104,2204,0,0,...
name4,1103,2206,0,0,...
....
其中,最后一个文件中的所有值列将是所有.csv文件的这些列中相应值的总和。因此,在结果文件中的value1下,我应该有1000+100+…+。。。等等
.csv文件的数量没有固定,所以我想我需要一个循环。
如何在Linux机器上使用bash脚本来实现这一点。谢谢
使用AWK
,尝试以下操作:
awk '
BEGIN {FS=OFS=","}
FNR==1 {header=$0} # header line
FNR>1 {
sum[FNR,1] = $1 # name column
for (j=2; j<=NF; j++) {
sum[FNR,j] += $j
}
}
END {
print header
for (i=2; i<=FNR; i++) {
for (j=1; j<=NF; j++) {
$j = sum[i,j]
}
print
}
}' *.csv
- 它在行和列上迭代,将值累积到模拟的二维数组
sum
中 - 您不必在csv文件上显式循环。AWK自动执行为你
- 读取所有csv文件后,它会报告
END
块中每行和每列的金额 - 请注意,gawk 4.0及更新版本支持true多维数组
希望这能有所帮助。
编辑
要计算平均值而不是总和,请尝试:
awk '
BEGIN {FS=OFS=","}
FNR==1 {header=$0} # header line
FNR>1 {
sum[FNR,1] = $1 # names column
for (j=2; j<=NF; j++) {
sum[FNR,j] += $j
}
}
END {
print header
files = ARGC - 1 # number of csv files
for (i=2; i<=FNR; i++) {
$1 = sum[i,1] # another treatment for the 1st column
for (j=2; j<=NF; j++) {
$j = sum[i,j] / files
# if you want to specify the number of decimal places,
# try something like:
# $j = sprintf("%.2f", sum[i,j] / files)
}
print
}
}' *.csv
使用Perl
/tmp> cat f1.csv
name,value1,value2,value3,value4
name1,100,200,0,0
name2,101,201,0,0
name3,102,202,0,0
name4,103,203,0,0
/tmp> cat f2.csv
name,value1,value2,value3,value4
name1,1000,2000,0,0
name2,1001,2001,0,0
name3,1002,2002,0,0
name4,1003,2003,0,0
/tmp>
/tmp> cat csv_add.ksh
perl -F, -lane '
@FH=@F if $.==1;
if($.>1) {
if( $F[0] ~~ @names )
{
@t1=@{ $kv{$F[0]} };
for($i=0;$i<$#t1-1;$i++) { $t1[$i]+=$F[$i+1] }
$kv{$F[0]}=[ @t1 ];
}
else {
$kv{$F[0]}=[ @F[1..$#F] ];
push(@names,$F[0]);
}
}
END { print join(" ",@FH); for(@names) { print "$_,".join(",",@{$kv{$_}}) }}
close(ARGV) if eof
' f1.csv f2.csv
/tmp>
/tmp> csv_add.ksh
name value1 value2 value3 value4
name1,1100,2200,0,0
name2,1102,2202,0,0
name3,1104,2204,0,0
name4,1106,2206,0,0
/tmp>