两个大文件的区别
我有“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 -q
和diff -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
使用grep
和bash
进程替换:
$ 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
如果行的顺序不相关,请使用awk
或perl
:
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.csv
和test2.csv
排序 -
uniq -u
:仅打印没有重复的行