【问题标题】:Is there an easy and fast solution to compare two csv files in bash?是否有一个简单快速的解决方案来比较 bash 中的两个 csv 文件?
【发布时间】:2021-03-28 12:19:51
【问题描述】:

我的问题: 我有 2 个大 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 你只想要与第二个文件的区别,但我不明白如何,因此我知道我剪切/删除了不需要的字符之后: 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,一次用 comms 得到不同的结果。所以我有点不确定,哪个是正确的方法^^

【问题讨论】:

  • 请发布其他 csv 文件的一些示例以进行测试和预期输出。将它们添加到您的问题中,不要将它们作为 cmets 或图像发布。谢谢。
  • 你只关心检查代码为,false的新文件吗?正确的方法是使用awk。否则,您最终会对每一个百万行文件进行多次传递。也就是说,要不要跳过其他文件中已经扫描过的常用名,true

标签: bash csv file grep diff


【解决方案1】:

给定:

$ 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

【讨论】:

    【解决方案2】:

    我认为对文件进行排序会占用大量资源。
    当您只想要新行时,可以尝试使用 grep 选项 -v

    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*
    

    【讨论】:

      【解决方案3】:

      是的!一个被高度低估的工具comm 非常适合这个。 从here 窃取的示例。

      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
      

      然后,您可以将该 diff 命令别名为“comp”或类似的名称,以允许您:

      comp 1.txt 2.txt
      

      如果这是您将来可能经常使用的命令,那可能会很方便。

      【讨论】:

      • +1 用于提及comm,但应指出输入文件需要事先排序;也许添加示例:comm -12 &lt;(sort a) &lt;(sort b) ?
      • @markp-fuso,这很好。我没有提到它,因为提到的原始海报已经对文件进行了排序,但最好是明确的。我已经添加了您的示例。
      • 请注意,这里的答案不限于 bash,据我所知,至少应该在 zsh 和 ksh 下工作。
      • @Roadowl 很好,它在鱼下对我有用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      相关资源
      最近更新 更多