【问题标题】:How to get the difference (only additions) between two files in linux如何获得linux中两个文件之间的差异(仅添加)
【发布时间】:2013-03-13 12:04:03
【问题描述】:

我有两个文件 A1 和 A2(未排序)。 A1 是 A2 的早期版本,并且在 A2 中添加了一些行。如何获取添加到 A2 的新行?

注意:我只想添加新行,而不想要 A1 中但在 A2 中删除的行。当我做diff A1 A2 时,我得到了添加和删除,但我只想要添加。

请提出一种方法来做到这一点。

【问题讨论】:

  • A2 中添加的所有行都是该文件的新行吗?我的意思是没有与现有行重复?

标签: linux bash diff


【解决方案1】:

以下大部分内容直接从@TomOnTime 的服务器故障答案here 复制而来。底部是对未排序文件的尝试,但该命令在给出差异之前对文件进行排序,因此在许多情况下它不会是所需的。对于未排序文件的格式良好的差异,您可能会发现其他答案更有用(感谢@Fritz 指出这一点):

显示仅存在于文件 a 中的行:(即从 a 中删除的内容)

comm -23 a b

显示仅存在于文件 b 中的行:(即添加到 b 中的内容)

comm -13 a b

显示只存在于一个文件或另一个文件中的行:(但不能同时存在)

comm -3 a b | sed 's/^\t//'

(警告:如果文件a 有以TAB 开头的行,它(第一个TAB)将从输出中删除。)

注意:两个文件都需要排序,“comm”才能正常工作。如果它们尚未排序,您应该对它们进行排序:

sort <a >a.sorted
sort <b >b.sorted
comm -12 a.sorted b.sorted

如果文件非常长,这可能是一个很大的负担,因为它需要额外的副本,因此需要两倍的磁盘空间。

编辑:请注意,可以使用进程替换更简洁地编写命令(感谢@phk 的评论):

comm -12 <(sort < a) <(sort < b)

【讨论】:

  • 由于我们在这里讨论的是bash,所以最后一个命令可以使用进程替换简化为comm -12 &lt;(sort &lt; a) &lt;(sort &lt; b)
  • 你先生,是我的英雄。
  • 为什么一个只适用于已排序文件的答案有如此多的赞成票,尽管问题明确指出这两个文件是未排序
  • 此答案包含在文件未排序时有效的命令(特别是最后一个)。我认为首先给出未排序的命令是有意义的,因为它们更容易理解,并构建到不假定排序的命令。
  • @scottkosty:感谢您的回复。抱歉,我在之前的评论中没有清楚地表达我的观点。我对这种方法的问题(与基于diff 的答案相反)是行的顺序被排序弄乱了,在许多 的情况下,顺序很重要。想象一下比较两个源代码文件以查看添加了哪个功能。只是,您在源代码之前按字母顺序排序... 对代码进行排序没有意义。这就是为什么我认为其他答案更好。我认为您至少应该在答案中的某处提及此警告。
【解决方案2】:

diff 然后grep 选择您想要的编辑类型。

diff -u A1 A2 | grep -E "^\+"

【讨论】:

  • 这将在行首留下+
  • 您可以使用 sed 删除那些:diff -u A1 A2 | grep '^\+' | sed -E 's/^\+//'
  • @AmauryD 您的编辑删除了第一行+++ A2,但在每行的开头留下了+ 符号,这就是上面的comment 和sed 命令的含义。跨度>
  • 您可以将grepsed 组合在一个命令中:diff -u A1 A2 | sed -n '/^+[^+]/ s/^+//p'
  • 缺点:此解决方案留下参考行号的行,例如@@ -31,6 +630,8 @@
【解决方案3】:

你可以试试这个

diff --changed-group-format='%>' --unchanged-group-format='' A1 A2

选项记录在man diff:

       --GTYPE-group-format=GFMT
              format GTYPE input groups with GFMT

和:

       LTYPE is 'old', 'new', or 'unchanged'.
              GTYPE is LTYPE or 'changed'.

和:

              GFMT (only) may contain:

       %<     lines from FILE1

       %>     lines from FILE2

       [...]

【讨论】:

  • 你能解释一下这些选项吗,我无法从手册页中得到它们
  • 查看此链接了解更多 gnu line group formats
  • --unchanged-group-format='' 之后的'' 看起来像一个单独的",这是行不通的。也许将'' 更改为"",以免有人用一个" 输入您的答案。
  • 这是一个比所选答案更好的答案,顺便说一句。为您提供您想要的,而不是在输出中散布+ 符号和不必要的元行。
  • 这是最好的答案,
【解决方案4】:

类似于https://stackoverflow.com/a/15385080/337172 的方法,但希望更易于理解和调整:

diff \
  --new-line-format="%L" \
  --old-line-format="" \
  --unchanged-line-format="" \
  A1 A2

【讨论】:

    【解决方案5】:

    您可以输入:

    grep -v -f A1 A2
    

    【讨论】:

    • 假设文件A1 包含一行x,文件A2 包含一行x 和另一行xx。此命令不输出任何内容,因为A2 中的两行都包含x
    • grep-x (--line-regexp) 可用于确保整行匹配。因此,如果 A1 包含 x 而 A2 包含 xx,则不会找到匹配项。
    • 您可能还需要使用选项-F--fixed-strings。否则grepA1 解释为正则表达式。因此,如果A1 包含.* 行,它将匹配所有内容。所以整个命令是:grep -vxF -f A1 A2
    【解决方案6】:

    简单的方法是使用:

    sdiff A1 A2
    

    另一种方法是使用comm,您可以在Comparing two unsorted lists in linux, listing the unique in the second file中看到

    【讨论】:

      【解决方案7】:
      git diff path/file.css | grep -E "^\+" | grep -v '+++ b/' | cut -c 2-
      
      • grep -E "^\+" 来自之前接受的答案,它不完整,因为留下了非源代码
      • grep -v '+++ b' 删除文件名为更高版本的非源代码行
      • cut -c 2- 删除+ 符号的列,也可以使用sed 's/^\+//'

      commsdiff 因为 git 而不是一个选项。

      【讨论】:

      • 最佳答案!这将准确返回已添加的行,仅此而已。我认为这应该是公认的答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 2021-12-28
      相关资源
      最近更新 更多