两个大文件的区别

我有“test1.csv”,它包含

200,400,600,800 100,300,500,700 50,25,125,310 

和test2.csv,它包含

 100,4,2,1,7 200,400,600,800 21,22,23,24,25 50,25,125,310 50,25,700,5 

现在

 diff test2.csv test1.csv > result.csv 

不同于

 diff test1.csv test2.csv > result.csv 

我不知道哪个是正确的顺序,但我想要别的东西,上面的两个命令都会输出类似的东西

 2 > 100,4,2,1,7 3 2,3c3,5 4 < 100,300,500,700 5  21,22,23,24,25 9 > 50,25,125,310 

我想只输出差异,因此results.csv应该是这样的

 100,300,500,700 100,4,2,1,7 21,22,23,24,25 50,25,700,5 

我尝试了diff -qdiff -s但他们没有做到这一点。 顺序无关紧要,重要的是我只想看到差异,没有>也不是空白。

grep -FvF在较小的文件上做了伎俩而不是在大文件上

第一个文件包含超过500万行,第二个文件包含1300个。

所以results.csv应该会产生~4,998,700行

我也尝试过grep -F -x -v -f ,它不起作用。

听起来像是一个comm工作:

 $ comm -3 <(sort test1.csv) <(sort test2.csv) 100,300,500,700 100,4,2,1,7 21,22,23,24,25 50,25,700,5 

man comm

  -1 suppress column 1 (lines unique to FILE1) -2 suppress column 2 (lines unique to FILE2) -3 suppress column 3 (lines that appear in both files) 

因此, -3表示只打印其中一个文件唯一的行。 但是,这些是根据找到它们的文件缩进的。要删除选项卡,请使用:

 $ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t' 100,300,500,700 100,4,2,1,7 21,22,23,24,25 50,25,700,5 

在这种情况下,您甚至不需要对文件进行排序,您可以将上述内容简化为:

 comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv 

使用grepbash进程替换:

 $ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) 100,300,500,700 100,4,2,1,7 21,22,23,24,25 50,25,700,5 

要将输出保存为results.csv

 cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv 
  • <()bash进程替换模式

  • grep -vFf test2.csv test1.csv将找到仅对test1.csv唯一的行

  • grep -vFf test1.csv test2.csv将找到仅对test2.csv唯一的行

  • 最后我们用cat总结了结果

或者正如Oli建议的那样 ,您也可以使用命令分组:

 $ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; } 100,300,500,700 100,4,2,1,7 21,22,23,24,25 50,25,700,5 

或者只是一个接一个地运行,因为他们都在写STDOUT,他们最终会被添加:

 $ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv 100,300,500,700 100,4,2,1,7 21,22,23,24,25 50,25,700,5 

如果行的顺序不相关,请使用awkperl

 awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv 

使用grep获取公共行并过滤掉它们:

 grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv 

内部grep获取公共行,然后外部grep查找与这些公共行不匹配的行。

使用diff--*-line-format=...选项

你可以准确地告诉diff你需要什么 – 解释如下:

 diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' f1.txt f2.txt 

可以以非常详细的方式指定diff的输出,类似于printf数字格式。

第一个文件test1.csv中的行称为“旧”行,而第二个test2.csv中的行是“新”行。 当diff用于查看文件中的更改时,这是有意义的。

我们需要的选项是设置“旧”行,“新”行和“未更改”行的格式。
我们需要的格式非常简单:
对于更改的行,新旧,我们只想输出行的文本。 %L是行文本的格式符号。
对于未更改的行,我们想要什么都不显示。

有了这个,我们可以使用你的示例数据编写像--old-line-format='%L' ,并将它们放在一起:

 $ diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' test1.csv test2.csv 100,4,2,1,7 100,300,500,700 21,22,23,24,25 50,25,700,5 

绩效说明

因为文件大小不同,尝试交换输入文件如果无关紧要,可能是diff的内部工作方式可以比另一方更好地处理。 更好的是需要更少的内存或更少的计算。

有一个优化选项可以将diff与大文件一起使用:– --speed-large-files 。 它使用了关于文件结构的假设,因此不清楚它是否对您的情况有帮助,但值得尝试。

格式选项在man diff中描述--LTYPE-line-format=LFMT

由于订单不需要保留,只需:

 sort test1.csv test2.csv | uniq -u 
  • sort test1.csv test2.csv :合并并对test1.csvtest2.csv排序
  • uniq -u :仅打印没有重复的行