连接重叠的文件,避免重复

连接重叠的文件,避免重复

假设我们有两个文本文件,我们想将它们合并为一个。

第二个文件以第一个文件中的行开头,因此它会重复其中的一部分。存在冗余重叠。

我怎样才能合并这些文件?

当然,理想情况下,欢迎针对一般二进制文件和多个部分的解决方案。

答案1

看似简短而甜蜜的解决方案是无处不在但也不祥的 awk 重复删除器:

awk '!x[$0]++'

它不仅删除重复项,还保留输入文件的原始顺序。这是该命令如何工作的解释:awk '!a[$0]++' 是如何工作的?

像这样使用

awk '!x[$0]++' file1 file2

它将先打印 file1,然后打印 file2,而不会重叠。由于重叠是重复的,因此将其删除。

但要小心!它将删除全部文件中的重复项。观察:

$ cat file1
a
b
b
overlap1
overlap2

$ cat file2
overlap1
overlap2
p
q
q

$ awk '!x[$0]++' file1 file2
a
b
overlap1
overlap2
p
q

它还删除了不重叠的重复行。

如果您的文件没有重复,或者您无论如何都想删除它们,那么这个命令就可以了。

如果您想保留重复的行,请继续阅读。

这是一种手动删除重叠而不删除重复项的方法。它可以自动化,但我没有付出努力。

首先从第一个文件中获取最后一行:

$ tail -n1 file1
overlap2

现在删除第二个文件中该行之前的所有行:

$ sed '0,/overlap2/d' file2
p
q
q

将 file1 与第二个命令的结果连接起来,您将得到连接的文件,没有重叠,但保留了重复项

$ cat file1 <(sed '0,/overlap2/d' file2)
a
b
b
overlap1
overlap2
p
q
q

这很有效,并且可能在大多数情况下都会有效。

但要小心!如果重叠有重复,这不会删除所有重叠。观察:

$ cat evil1
a
b
overlap1
overlap2
overlap3
overlap1
overlap2

$ cat evil2
overlap1
overlap2
overlap3
overlap1
overlap2
p
overlap2
q

确定第一个文件的最后一行

$ tail -n1 evil1
overlap2

从第二个文件中删除第一次出现的位置

$ sed '0,/overlap2/d' evil2
overlap3
overlap1
overlap2
p
overlap2
q

当重叠中存在重复时,仅删除第一次出现的位置并不能删除所有重叠。但由于杂散overlap2线,我们也不能只删除最后一次出现的情况。

那么如何确定最大重叠呢?首先在 file2 中查找 file1 中最后一行的每一次出现。对于每个出现测试是否重叠。然后取最后一次仍然重叠的事件。

找到每一个出现的地方

$ grep -n overlap2 evil2
2:overlap2
5:overlap2
7:overlap2

测试每个是否重叠

$ diff -q <(tail -n2 evil1) <(head -n2 evil2)

$ diff -q <(tail -n5 evil1) <(head -n5 evil2)

$ diff -q <(tail -n7 evil1) <(head -n7 evil2)
Files /dev/fd/63 and /dev/fd/62 differ

没有输出意味着没有区别。两条线重叠。五行也是重叠的。但七条线不再重叠。这意味着第 5 行的出现是最大重叠,而第 7 行的出现与重叠无关。

$ cat evil1 <(sed '1,5d' evil2)
a
b
overlap1
overlap2
overlap3
overlap1
overlap2
p
overlap2
q

正如所说,这可以自动化,但我没有付出努力。

相关xkcd:https://xkcd.com/974/

至少我为这个答案付出了努力。享受。

答案2

如果顺序不重要,您可以使用以下命令来完成工作:

sort -u FILE1 FILE2 > FILE3

如果文件的顺序很重要,请使用以下命令:

cat -n FILE1 FILE2 | sort -uk2 | sort -nk1 | cut -f2- > FILE3

相关内容