我对 awk 没有太多经验,所以我很难克服它的一个问题。我有两个名为 file1.txt 和 file2.txt 的文件。文件1.txt:
20 101 1 2 3 4
20 102 5 6 7 8
20 108 3 3 3 3
文件2.txt:
20 100 99 99 99 99
20 101 11 22 33 44
20 103 55 66 77 88
每个文件中前两列之后始终有 4 个值。
我想做的是将这些文件合并为一个。我将通过第一列和第二列加入他们。
生成的文件中应有 10 列。前两列是关键列,接下来的 4 列是第一个文件中的值,最后 4 列来自第二个文件。
在生成的文件中,第一个文件中与第二个文件不匹配的每条记录(反之亦然)将具有表示缺失值的附加零。
一切都由空格字符分隔。
结果应该是这样的:
20 100 0 0 0 0 99 99 99 99
20 101 1 2 3 4 11 22 33 44
20 102 5 6 7 8 0 0 0 0
20 103 0 0 0 0 55 66 77 88
20 108 3 3 3 3 0 0 0 0
这是我的 awk 脚本,是我根据在网上搜索时找到的脚本进行修改的:
BEGIN {
OFS=" "
}
{
i=$1 OFS $2 #Making key out of first and second field of the first file
}
NR==FNR {
A[i]=$0 #Saving records from first file to an array using first two columns as index
next
}
#Next part assumes that I'm reading file2.txt
i in A {
printf "%s",A[i] #Here, I have a match with first file, and I want to print the joined record I saved from file1.txt
print $3,$4,$5,$6 #In order to print a joined record, after printing record from first file, I'm printing columns from the second file
delete A[i]
next
}
{ #Here I print records from file2.txt that don't have a match with file1.txt, and put zeroes to fill missing values
print 0,0,0,0,$3,$4,$5,$6
}
END { #In the END block I'm printing everything from file1.txt that doesn't have a match and print zeroes aftewards to fill missing values
for (i in A) { printf "%s",A[i]; print 0,0,0,0 }
}
结果按第二列排序,所有缺失值均用零填充。但是,我目前得到的结果如下所示:
20 100 0 0 0 0 99 99 99 99
11 22 33 443 4
20 103 0 0 0 0 55 66 77 88
20 108 3 3 3 3 0 0 0 0
0 0 0 0 6 7 8
尽管文件没有排序(我总是可以使用 sort -k 2),但有些行没有按照我预期的方式打印,而且我无法解释为什么它不能正常打印 A 的元素大批。我尝试过各种方法,例如暂时更改 ORS (根本没有输出)或使用 print 而不是 printf (结果看起来也很奇怪)。
由于缺乏经验,这引发了一些额外的问题:
使用awk来完成这个任务是否合理?我尝试过使用加入,但最终陷入困境,因为它无法打印末尾带有换行符的列。也许 Python 脚本会更有用?
考虑到我将使用非常大的文件进行合并,在内存方面使用数组是否合理?
提前致谢!
答案1
awk '!second { file1vals[$1 FS $2]=$0 }
second { print (($1 FS $2 in file1vals)?file1vals[$1 FS $2]: $1 FS $2 FS "0 0 0 0") FS $3, $4, $5, $6;
delete file1vals[$1 FS $2]
}
END{ for(x in file1vals) print file1vals[x], "0 0 0 0" }' file1 second=1 file2
只要有足够的内存来加载第一个,这就会起作用文件1进入记忆。
在第一个块中!second {...}
,它仅在它是第一个文件并且我们加载时运行文件1放入第一列和第二列对上的关联数组中作为数组的键。
在第二个块中second {...}
,它仅在第二个文件时运行,我们打印两个文件中具有匹配键的连接行,否则我们打印键和 0,后跟其余列文件2;然后我们还从delete file1vals[$1 FS $2]
两个文件中都存在密钥的数组中删除密钥。
在末尾的最后一个块中,我们打印与以下内容相关的剩余不匹配键文件1。