在bash中比较两个csv文件是否有简单快捷的解决方案?

3
我的问题: 我有两个包含数百万行的大型csv文件。
其中一个文件包含我的服务器数据库的备份,看起来像:
securityCode,isScanned
NALEJNSIDO,false
NALSKIFKEA,false
NAPOIDFNLE,true
...

现在我有另一个CSV文件,包含新的代码,具有完全相同的模式。
我想比较这两个文件,并且只找到那些不在服务器上的代码。因为我的朋友生成随机代码,我们想要确保只更新尚未在服务器上的代码。
我尝试使用 sort -u serverBackup.csv > serverBackupSorted.csvsort -u newCodes.csv > newCodesSorted.csv 将它们排序。
首先,我尝试使用 grep -F -x -f newCodesSorted.csv serverBackupSorted.csv,但进程被终止,因为它消耗了太多资源,所以我认为必须有更好的方法。
然后我使用了diff来查找newCodesSorted.csv中的新行,例如diff serverBackupSorted.csv newCodesSorted.csv
我相信你可以直接告诉diff你只想要第二个文件的差异,但是我没有理解如何实现,因此我使用了grep输入,知道稍后会剪切/删除不需要的字符: diff serverBackupSorted.csv newCodesSorted.csv | grep '>' > greppedCodes 但我相信必须有更好的方法。
因此,我问你是否有任何想法可以改进这种方法。
编辑:
到目前为止,comm效果很好。但是,我忘了提到服务器上的某些代码已经被扫描过了。
但是新代码始终使用isScanned = false进行初始化。因此,newCodes.csv看起来像这样:
securityCode,isScanned
ALBSIBFOEA,false
OUVOENJBSD,false
NAPOIDFNLE,false
NALEJNSIDO,false
NPIAEBNSIE,false
...

我不知道是否足够使用“cut -d',' -f1”仅保留代码并使用命令。

我尝试过使用grep和命令,但得到了不同的结果。所以我有点不确定哪一个是正确的方法^^


请提供一些其他CSV文件的样本进行测试,并附上预期输出。请将它们添加到您的问题中,而不要作为评论或图片发布。谢谢。 - James Brown
你只关心检查代码中的新文件,其中代码是,false吗?正确的方法是使用awk。否则,你将会对每个拥有百万行的文件进行多次遍历。换句话说,你想要跳过其他文件中已经被扫描过的常见名称,即,true吗? - David C. Rankin
3个回答

4

没错!一个被高度低估的工具 comm 在这方面非常棒。 以下示例来自这里

Show lines that only exist in file a: (i.e. what was deleted from a)
comm -23 a b

Show lines that only exist in file b: (i.e. what was added to b)
comm -13 a b

Show lines that only exist in one file or the other: (but not both)
comm -3 a b | sed 's/^\t//'

As noted in the comments, for comm to work the files do need to be sorted beforehand. The following will sort them as a part of the command:
comm -12 <(sort a) <(sort b)

如果您更喜欢使用diff,您可以让它在不需要grep的情况下实现您想要的功能:

diff --changed-group-format='%<%>' --unchanged-group-format='' 1.txt 2.txt

你可以将该差异命令别名为“comp”或类似的名称,以便你只需执行以下操作:
comp 1.txt 2.txt

如果您将来可能经常使用此命令,则这可能很方便。

1
+1 提到了 comm,但需要指出输入文件在使用之前需要进行排序;可以添加示例:comm -12 <(sort a) <(sort b) - markp-fuso
1
@markp-fuso,这是一个很好的观点。我没有提到它,因为原帖中提到已经整理好了文件,但明确一点会更好。我已经加入了你的例子。 - axwr
1
请注意,这里的答案不仅限于bash,据我所知,至少在zsh和ksh下也可以工作。 - user2849202
@Roadowl 很好的观点,在我看来,这对我来说是可行的。 - axwr

0
我觉得对文件进行排序会消耗很多资源。 当你只想要新的行时,你可以尝试使用带有选项-v的grep命令。
grep -vFxf serverBackup.csv newCodes.csv 

或者首先拆分serverBackup.csv

split -a 4  --lines 10000 serverBackup.csv splitted
cp newCodes.csv newCodes.csv.org
for f in splitted*; do
   grep -vFxf "${f}" newCodes.csv > smaller
   mv smaller newCodes.csv
done
rm splitted*

0
给定:
$ cat f1
securityCode,isScanned
NALEJNSIDO,false
NALSKIFKEA,false
NAPOIDFNLE,true

$ cat f2
securityCode,isScanned
NALEJNSIDO,false
NALSKIFKEA,true
NAPOIDFNLE,false
SOMETHINGELSE,true

你可以使用awk:
$ awk 'FNR==NR{seen[$0]; next} !($0 in seen)' f1 f2
NALSKIFKEA,true
NAPOIDFNLE,false
SOMETHINGELSE,true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接