假设我有两个文件 a.txt、b.txt
a.txt
87621 3bde NDF
87621 2dfg NDF
87621 cdef NDF
87621 abcd NDF
b.txt
93291 abcd NDF
93291 2dfg NDF
93291 adbf NDF
93291 gdrg NDF
我的脚本应该创建一个文件,通过匹配两个文件的第 2 列,并在新文件 c.txt 中创建一个具有匹配字符串的文件,如下所示
c.txt
2dfg
abcd
我尝试了几种方法,但没有成功,你能帮忙吗!
答案1
这将读取所有行a.txt
并跟踪其第 2 列的所有值。然后读取b.txt
并打印出第 2 列的任何重复值:
$ awk 'NR==FNR {seen[$2]=1; next} seen[$2]==1 {seen[$2]++; print $2}' a.txt b.txt
abcd
2dfg
该awk
命令可分为两部分。第一部分是:
NR==FNR {seen[$2]=1; next}
awk
首先测试处理的记录(行)总数 是否NR
与此文件中处理的记录数 相同FNR
。这仅适用于处理的第一个文件,a.txt
在本例中为 。因此,对于 中的每一行,将键设置为第二列的值的a.txt
关联数组设置为 的值。这将用于指示 中“看到”了列 2 的这个值。以下命令是 ,它指示跳过其余命令并获取下一个记录。seen
$2
1
a.txt
next
awk
第二部分是:
seen[$2]==1 {seen[$2]++; print $2}
由于next
上面第一部分中的命令,此部分仅由文件执行b.txt
。此部分以测试开始:它检查此$2
记录的列 2 值 是否以前出现过。如果 以前出现过一次,则执行括号中的命令。括号中的第一个命令seen[$2]++
将 的值递增,seen
以便我们永远不会再次处理列 2 的这个值。(因此,列 2 的重复值将被忽略。)第二个命令只是打印 以前在 中出现过的列 2 的值a.txt
。
如果我们可以相信第 2 列没有重复的值,那么可以使用更简单的脚本:
$ awk '{print $2}' a.txt b.txt | sort | uniq -d
2dfg
abcd
答案2
comm -12 <(awk '{print $2}' a.txt | sort) <(awk '{print $2}' b.txt | sort) > c.txt
解释
<(...)
是流程替代. 即 中的命令的输出(...)
被替换并用作 的两个输入comm
。awk '{print $2}' a.txt
仅打印每行的第二个字段。sort
将准备输入的输出进行排序comm
。comm
比较两个已排序的文件。-12
标志会隐藏每个文件所特有的行,而只打印公共行(man comm
有关详细信息,请参阅)。
答案3
下面的 perl 单行命令可以完成这个工作:
perl -lane 'BEGIN{%h}$h{$ARGV."\n".$F[1]}++;END{foreach(keys(%h)){s/.*\n//;$f{$_}++};for(keys(%f)){print if$f{$_}>1}}' a.txt b.txt > c.txt