我希望比较两个文件,仅打印具有匹配 ID 号的记录,并且不打印重复记录。
我有两个文件:
file1.txt
包含:
Simons 0987768798980
West 09809867678
Vickers 768774564650
Simons 76867790987
Peterson 24346576865
Simons 76867790987
Holister 87879655456
Peterson 87686765766
并且,file2.txt
包含:
768774564650 Harry
76867790987 Steve
0987768798980 Mary
0987768798980 Mary
76856009097 Ali
87879655456 Rick
87686765766 Martin
期望的结果是:
Harry Vickers 768774564650
Steve Simons 76867790987
Mary Simons 0987768798980
Rick Holister 87879655456
Martin Peterson 87686765766
这是我尝试过的:
ARGV[1]==FILENAME{id2lastname[$2]=$1;id2id[$2]=$2}
ARGV[2]==FILENAME{id2firstname[$1]=$2}
$1 in id2id{print id2firstname[$1],id2lastname[$1],id2id[$1],id2firstname[$1]="",id2id[$1]="",id2lastname[$1]=""}
产生以下输出:
Harry Vickers 768774564650
Steve Simons 76867790987
Mary Simons 0987768798980
Mary
Rick Holister 87879655456
Martin Peterson 87686765766
我很高兴知道为什么删除了重复记录的姓氏和 ID 号,但保留了名字。
如果该技术很奇怪或非常规,我们深表歉意。我学习的时间不长。
如果我的尝试无法修复或者您觉得有更好的方法,我很高兴您以不同的方式产生所需的结果,但请:
- 使用 GAWK (因为我想继续使用它),
- 尽量保持简单,
- 并且解释它是如何工作的,这样我就可以学到一些东西。
答案1
打印部分行的原因是,在代码中,您不是删除要从数组中删除的值,而是用空字符串替换它们的值。
这会导致检查$1 in id2id{ ... }
评估为true
空字符串值。
解决方案是将代码替换id2id[$1]=""
为delete id2id[$1]
,然后它应该按预期工作。
这是代码的稍微简化版本:
awk 'NR == FNR { a[$2] = $1; next }
$1 in a { print a[$1], $2, $1; delete a[$1] }' file1.txt file2.txt
在一行中:
awk 'NR==FNR{a[$2]=$1;next} $1 in a{print a[$1],$2,$1; delete a[$1]}' file1.txt file2.txt
使用 awk 代替 join 的优点是简单且易于定制。
缺点是在合并之前将第一个文件存储在RAM中,因此不能有效地处理大文件。
答案2
根据您的需要使用join
,使其尽可能简单;
join -1 2 -2 1 -o 2.2 1.1 2.1 <(sort -unk2,2 file1) <(sort -unk1,1 file2) 2>/dev/null
join
在第一个文件的第二个字段上-1 2
,以第二个文件的第一个字段-2 1
作为键。
并-o
输出这些字段:
第二个文件中的第二个字段2.2
第一个文件中的第一个字段1.1
和第二个文件中的第一个字段2.1
这将第二个字段上的第一个文件作为键进行数字排序sort -unk2,2 file1
,并将第一个字段上的第二个文件作为数字键进行排序,并从两个文件中sort -unk1,1 file2
删除重复项。-u
awk解决方案:
awk '!second_file{ Ids[$2]=$1; next }
($1 in Ids) { print $2, Ids[$1], $1 }' file1 second_file=1 <(sort -u file2)