查找两个文件之间的公共行以及它们的行号

时间:2013-12-20 13:07:34

标签: bash shell

我想找到两个文件(大文件)之间的公共线,一个有9千万行,1个有10万个,还有它们的行号。

comm -12 file1 file2

给了我常用的行,但我想知道单个文件中的行号

3 个答案:

答案 0 :(得分:2)

此解决方案适用于我的小型测试文件 - 我不确定它将如何在包含9000万行的文件上执行。

tab=` printf '\t' `
join -t"$tab" -j2 <( cat -n file1 ) <( cat -n file2 )

这是有效的,因为cat -n会在每行前面添加一个空格填充的数字后跟一个制表符。然后join找到公共线,只查看第一个标签后的内容。

连接完成后,您应该看到公共线,每条线后跟两个数字。第一个数字是file1的行号,第二个是file2。

警告:如果文件中没有制表符,这将有效。如果不是这种情况,您可以使用sed将第一个标签转换为“安全”字符。

safe="|"
join -t"$safe" -j2 \
  <( cat -n file1 | sed -e "s:\t:$safe:" ) \
  <( cat -n file2 | sed -e "s:\t:$safe:" )

此外,根据join的实现方式,您可能希望在第一个进程替换中列出较小的文件,在第二个进程替换中列出较大的文件。这样,较小的文件可以全部适合存储器,并且可以扫描较大的文件并有效地选择匹配的行。我不知道是不是这样,但它可能值得一试。

答案 1 :(得分:0)

您可以尝试:

awk '
FNR==NR {
    a[$0]++
    next
}
$0 in a {
    print
    delete a[$0]
}' file1 file2

如果您还想获取行号,可以使用gawk版本4中的数组数组,如:

FNR==NR {
    a[$0][FNR]++
    file1=FILENAME
    next
}
FNR==1 {
    file2=FILENAME
}

$0 in a {
    b[$0][FNR]++
}

END {
    for(i in b) {
        print "Line: " i
        print " Line numbers in "file1":"
        printf "  "
        for (j in a[i])
            printf "%s,", j
        print ""
        print " Line numbers in "file2":"
        printf "  "
        for (j in b[i])
            printf "%s,", j
        print ""
    }
}

答案 2 :(得分:0)

你可以用diff到达那里。这会显示file1中的行号,但不幸的是,似乎没有任何选项显示来自file2的行号 - 似乎man diff假设未更改的行也是在两个文件中的相同的行,这与它通常的工作方式相反。

diff --unchanged-line-format=$'%dn\t%L' --old-line-format='' --new-line-format='' file1 file2

使用unified diff的另一半措施:

diff -u file1 file2

这显示了带有一些上下文的不同的行,这意味着您可以推断公共文本所在的行。以@@开头的行为您提供行信息。例如:

@@ -1,5 +2,10 @@

这意味着以-开头的下一行或差异中的空格是file1中的第1行,而下一行以+开头或空格是第2行file2。为了您的目的,您可以忽略逗号后面的数字。