我有很多文件(我以5个为例)
如果与第一个文件不匹配,则应在输出中添加0
文件1
1001 1 2
1002 1 2
1003 3 5
1004 6 7
1005 8 9
1009 2 3
文件2
1002 7
1003 8
文件3
1001 5
1002 3
文件4
1002 10
1004 60
1007 4
文件5
1001 102
1003 305
1005 809
所需的输出
1001 1 2 0 5 0 102
1002 1 2 7 3 10 0
1003 3 5 8 0 0 305
1004 6 7 0 0 60 0
1005 8 9 0 0 0 809
1007 0 0 0 0 4 0
1009 2 3 0 0 0 0
使用下面的代码,我可以合并两个文件,但是如何合并所有文件
awk 'FNR==NR{a[$1]=$2;next}{print $0,a[$1]?a[$1]:"0"}' file2 file1
1001 1 2 0
1002 1 2 7
1003 3 5 8
1004 6 7 0
1005 8 9 0
预先感谢
答案 0 :(得分:5)
GNU加入救援!
$ join -a1 -a2 -e '0' -o auto file1 file2 \
| join -a1 -a2 -e '0' -o auto - file3 \
| join -a1 -a2 -e '0' -o auto - file4 \
| join -a1 -a2 -e '0' -o auto - file5
选项-a1
和-a2
告诉join
插入缺少的字段。 -e '0'
告诉它用零代替它们。输出用-o auto
指定,它假定采用所有字段。
当有大量文件时,不能使用管道构造,但可以使用简单的for循环:
out=output
tmp=$(mktemp)
[[ -e "$out" ]] && rm -rf "$out" || touch "$out"
for file in f*; do
join -a1 -a2 -e0 -o auto "$out" "$file" > "$tmp"
mv "$tmp" "$out"
done
cat "$out"
或者如果您真的喜欢管道:
pipeline="cat /dev/null"
for file in f*; do pipeline="$pipeline | join -a1 -a2 -e0 -o auto - $file"; done
eval "$pipeline"
这里非常有趣: Is there a limit on how many pipes I can use?
备注:在这种情况下,auto
的使用非常有用,但不是POSIX standard的一部分。它是GNU扩展,属于GNU coreutils的一部分。纯粹的POSIX版本会更麻烦一些:
$ join -a1 -a2 -e '0' -o 0 1.2 2.2 file1 file2 \
| join -a1 -a2 -e '0' -o 0 1.2 1.3 2.2 - file3 \
| join -a1 -a2 -e '0' -o 0 1.2 1.3 1.4 2.2 - file4 \
| join -a1 -a2 -e '0' -o 0 1.2 1.3 1.4 1.5 2.2 - file5
有关man join
的更多信息
答案 1 :(得分:3)
对于真正的多维数组,使用GNU awk和sorted_in:
$ cat tst.awk
FNR==1 { numCols = colNr }
{
key = $1
for (i=2; i<=NF; i++) {
colNr = numCols + i - 1
val = $i
lgth = length(val)
vals[key][colNr] = val
wids[colNr] = (lgth > wids[colNr] ? lgth : wids[colNr])
}
}
END {
numCols = colNr
PROCINFO["sorted_in"] = "@ind_num_asc"
for (key in vals) {
printf "%s", key
for (colNr=1; colNr<=numCols; colNr++) {
printf "%s%*d", OFS, wids[colNr], vals[key][colNr]
}
print ""
}
}
$ awk -f tst.awk file*
1001 1 2 0 5 0 102
1002 1 2 7 3 10 0
1003 3 5 8 0 0 305
1004 6 7 0 0 60 0
1005 8 9 0 0 0 809
1007 0 0 0 0 4 0
1009 2 3 0 0 0 0
答案 2 :(得分:2)
使用GNU awk
awk '
NR>FNR && FNR==1{
colcount+=cols
}
{
for(i=2;i<=NF;i++){
rec[$1][colcount+i-1]=$i
}
}
{
cols=NF-1
}
END{
colcount++
for(ind in rec){
printf "%s%s",ind,OFS
for(i=1;i<=colcount;i++){
printf "%s%s",rec[ind][i]?rec[ind][i]:0,OFS
}
print ""
}
}' file{1..5} | sort -k1 | column -t
输出
1001 1 2 0 5 0 102
1002 1 2 7 3 10 0
1003 3 5 8 0 0 305
1004 6 7 0 0 60 0
1005 8 9 0 0 0 809
1006 0 0 0 0 0 666
注意:将适用于here所述的情况以及任何类型的值。