我有许多具有相同标题的文件:
COL1,COL2,COL3,COL4
您可以忽略COL1-COL3。 COL4包含一个数字。每个文件包含大约200行。我试图总结各行。例如:
档案1
COL1 COL2 COL3 COL4
x y z 5
a b c 10
文件2
COL1 COL2 COL3 COL4
x y z 8
a b c 14
然后返回一个新文件:
{{1}}
有没有没有 AWK的简单方法?如果需要,我会使用AWK,我只是觉得可能有一个简单的单行程,我可以立即运行。我想到的AWK脚本感觉有点长。
由于
答案 0 :(得分:2)
如果所有文件都具有相同的标题 - awk 解决方案:
awk '!f && FNR==1{ f=1; print $0 }FNR>1{ s[FNR]+=$NF; $NF=""; r[FNR]=$0 }
END{ for(i=2;i<=FNR;i++) print r[i],s[i] }' File[12]
输出(2个文件):
COL1 COL2 COL3 COL4
x y z 8
a b c 14
此方法可应用于多个文件(在这种情况下,您可以为文件名扩展指定 globbing File*
)
答案 1 :(得分:2)
将paste
与awk
结合起来,就像Kristo Mägi's answer一样,是您最好的选择:
paste
合并输入文件中的相应行awk
,每个输入行包含要汇总的所有字段。假设输入文件和列的数量固定,Kristo的答案可以简化以使处理更加高效:
paste file1 file2 | awk '{ print $1, $2, $3, (NR==1 ? $4 : $4 + $8) }'
注意:上面会生成 space - 分隔的输出列,因为awk
的输出字段分隔符OFS
的默认值是是一个单一的空间。
假设所有文件具有相同的列结构和行数,下面是解决方案的概括,其中:
#!/bin/bash
files=( file1 file2 ) # array of input files
paste "${files[@]}" | awk -v numFiles=${#files[@]} -v OFS='\t' '
{
row = sep = ""
for(i=1; i < NF/numFiles; ++i) { row = row sep $i; sep = OFS }
sum = $(NF/numFiles) # last header col. / (1st) data col. to sum
if (NR > 1) { for(i=2; i<=numFiles; ++i) sum += $(NF/numFiles * i) } # add other cols.
printf "%s%s%s\n", row, OFS, sum
}
'
请注意,\t
(标签字符。)用于分隔输出字段,并且由于依赖awk
的默认行拆分字段,保留了确切的输入字段之间的空白无法保证。
答案 2 :(得分:1)
你说你有很多文件&#34;。即超过2.
鉴于这3个文件(并且可以使用任何数字):
$ cat f1 f2 f3
COL1 COL2 COL3 COL4
x y z 3
a b c 4
COL1 COL2 COL3 COL4
x y z 5
a b c 10
COL1 COL2 COL3 COL4
x y z 10
a b c 15
你可以这样做:
$ awk 'FNR==1{next}
{sum[$1]+=$4}
END{print "COL1 COL4";
for (e in sum) print e, sum[e]} ' f1 f2 f3
COL1 COL4
x 18
a 29
目前还不清楚你打算用COL2或COL3做什么,所以我没有添加它。
答案 3 :(得分:1)
还有一个选择。
命令:
paste f{1,2}.txt | sed '1d' | awk '{print $1,$2,$3,$4+$8}' | awk 'BEGIN{print "COL1","COL2","COL3","COL4"}1'
结果:
COL1 COL2 COL3 COL4
x y z 8
a b c 14
它的作用:
测试文件:
$ cat f1.txt
COL1 COL2 COL3 COL4
x y z 3
a b c 4
$ cat f2.txt
COL1 COL2 COL3 COL4
x y z 5
a b c 10
命令:paste f{1,2}.txt
连接2个文件并输出:
COL1 COL2 COL3 COL4 COL1 COL2 COL3 COL4
x y z 3 x y z 5
a b c 4 a b c 10
命令:sed '1d'
意味着暂时删除标题
命令:awk '{print $1,$2,$3,$4+$8}'
返回COL1-3并从粘贴结果中总结$ 4和$ 8。
命令:awk 'BEGIN{print "COL1","COL2","COL3","COL4"}1'
添加标题
编辑:
关注@ mklement0评论,他对标题处理是正确的,因为我忘记了NR==1
部分。
所以,我也会在这里代理他的更新版本:
paste f{1,2}.txt | awk '{ print $1, $2, $3, (NR==1 ? $4 : $4 + $8) }'
答案 4 :(得分:0)
$ awk '
NR==1 { print }
{ sum[FNR]+=$NF; sub(/[^[:space:]]+[[:space:]]*$/,""); pfx[FNR]=$0 }
END { for(i=2;i<=FNR;i++) print pfx[i] sum[i] }
' file1 file2
COL1 COL2 COL3 COL4
x y z 8
a b c 14
上述任何UNIX系统上的任何awk都可以健壮有效地工作,具有任意数量的输入文件和这些文件的任何内容。唯一可能的问题是它必须在内存中保留相当于1个这样的文件,所以如果每个文件都非常庞大,那么你可能会耗尽可用内存。