如何获取差异以仅显示添加和删除的行?如果diff无法做到,那么什么工具可以呢?


69

如何获取差异以仅显示添加和删除的行?如果diff无法做到,那么什么工具可以呢?


2
您需要更好地定义添加和删除的含义。具体来说,线可以改变吗?如果是这样,您如何处理更改的行?如果执行严格的面向行的检查,则更改的行与要删除的旧行和要添加的新行相同。例如,它应该如何处理一分为二的行?由于两个1线改变了?2行改了吗?删除1条线并添加2条线?除非您能保证行永远不会改变,而只是添加和删除,否则我认为如果没有更好的定义,这注定会失败。
Christopher Cashell

我觉得这个问题还不清楚。但是至少可以用以下方式回答这个问题diff A B | grep '^[<>]'
kasperd 2014年

您可能正在寻找comm
珍妮·D

@ChristopherCashell,他的意思是忽略排序顺序;一个典型的常见问题。通常,这是通过在进行典型差异之前首先对每一侧的线段(线)进行排序来完成的。
佩里耶

@Pacerier,您确定吗?还是在猜?问题中未提及或暗示任何有关排序或搜索顺序的信息。就目前而言,这个问题尚不清楚,可以用许多不同的方式来解释。不知道可以肯定他是问什么,我们正在做的假设,并提供可能会或可能不会解决实际问题的解决方案。此外,在其中一个答案楼主的意见建议,这是相关的排序。它确实与“添加和删除”与“更改”的含义有关。
Christopher Cashell

Answers:


81

尝试通讯

另一种查看方式:

  • 显示仅存在于文件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

如果文件过长,则可能会很麻烦,因为它需要额外的副本,因此需要两倍的磁盘空间。


5
只是想补充一下,此解决方案必须对两个文件进行排序(区分大小写)才能产生正确的结果
marmor 2014年

在足够现代的外壳上,您可以按以下方式进行内联排序comm -12 <(sort a) <(sort b)
Joshua Huber

14

comm可能会做您想要的。从其手册页:

描述

逐行比较排序的文件FILE1和FILE2。

如果没有选项,则产生三列输出。第一列包含FILE1独有的行,第二列包含FILE2独有的行,第三列包含两个文件共同的行。

这些列是suppressable用-1-2-3分别。

例:

[root@dev ~]# cat a
common
shared
unique

[root@dev ~]# cat b
common
individual
shared

[root@dev ~]# comm -3 a b
    individual
unique

而且,如果您只想要唯一的行,而不关心它们位于哪个文件中:

[root@dev ~]# comm -3 a b | sed 's/^\t//'
individual
unique

如手册页所述,必须事先对文件进行排序。


9

要显示没有上下文的添加和删除,请使用行号+,-,<,>!等等,您可以像这样使用diff:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

例如,给定两个文件:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

以下命令将显示从a删除或添加到b的行:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

输出:

B-ONLY
A-ONLY

这个略有不同的命令将显示从a.txt中删除的行:

diff --changed-group-format='%<' --unchanged-group-format='' a.txt b.txt 

输出:

A-ONLY

最后,此命令将显示添加到a.txt中的行

diff --changed-group-format='%>' --unchanged-group-format='' a.txt b.txt 

输出

B-ONLY

2

这就是diff在默认情况下所做的...也许您需要添加一些标志来忽略空格?

diff -b -B

应该忽略空白行和不同数量的空格。


1
不,它还显示CHANGED行(具有一个字符或四个不同的行)。我想要仅存在于左侧或右侧的线。
罗斯

2
您可能会争辩说,CHANGED文件的不同版本仅存在于左侧或右侧。
markdrayton

2
diff(或任何其他工具)无法可靠地告知更改内容以及删除的行被新行替换。
慈安

1
从技术上讲,diff将“更改的”行视为删除了原始行并添加了新行...因此从技术上讲,它仅显示已添加和删除的行。
KFro

2

不,diff实际上并没有以人们可能想到的方式显示两个文件之间的差异。它为工具(例如patch用来将一个文件转换为另一个文件)产生一系列编辑命令。

任何尝试做您要寻找的问题的难点在于,如何定义构成变化的线与删除的线和添加的线的关系。另外,添加,删除和更改彼此相邻的行时该怎么办。


我的想法正好。为了将其视为新字符而不是对原始字符的修改,必须更改一行字符的百分比?从技术上讲,即使您有一个共同的字符,也可以将其视为“更改”,而不是删除和插入。
卡米尔·基西尔

1
自从查看diff来源以来已经有很长时间了,但是我似乎还记得各种旋转方式来跟踪两个文件的匹配位置以保持同步,并且我认为根据放弃的距离有多大的门槛线是。但是我不记得任何行内匹配,除了(可选)折叠的空白或忽略大小写。或(也许)话语影响。无论如何,这就是一切patch,“ vgrep”就随它而来。也许。星期二。
丹尼斯·威廉姆森,2009年

2

视觉比较工具将两个文件放在一起,因此具有相同行数但内容不同的段将被视为已更改的段。匹配段之间的全新行被视为添加的段。

sdiff命令行工具也是如此,它显示了终端中两个文件的并排比较。换行用|分隔。字符。如果仅在文件A中存在一行,则将<用作分隔符。如果仅在文件B中存在一行,则将>用作分隔符。如果文件中没有<和>字符,则可以使用此字符仅显示添加的行:

sdiff A B | grep '[<>]'

2

感谢senarvi,您的解决方案(未经投票)实际上为我提供了我想要的东西,经过一千吨的页面寻找。

使用您的答案,这是我想出的更改/添加/删除内容的清单。该示例使用/ etc / passwd文件的2个版本,并打印出相关记录的用户名。

#!/bin/bash
sdiff passwd1 passwd2 | grep '[|]' | awk -F: '{print "changed: " $1}'
sdiff passwd1 passwd2 | grep '[<]' | awk -F: '{print "deleted: " $1}'
sdiff passwd1 passwd2 | grep '[>]' | awk -F\> '{print $2}' | awk -F: '{print "added: " $1}'

注意,因为“已修改一行”和“已删除一行并在其下方或上方添加了另一行”之间的区别是语义上的。基于通用文本的差异工具无法区分这些情况。结果,您基于sdiff的答案无法在所有情况下可靠地工作。
Mikko Rantalainen'2

0

我发现这种特殊形式通常很有用:

diff --changed-group-format='-%<+%>' --unchanged-group-format='' f g

例:

printf 'a\nb\nc\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

输出:

-b
-c
+B
+C
-e
-f
+E
+F

因此它显示的是旧行,-紧随其后的是对应的新行+

如果我们删除了C

printf 'a\nb\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

它看起来像这样:

-b
+B
+C
-e
-f
+E
+F

该格式记录在man diff

       --line-format=LFMT
              format all input lines with LFMT`

和:

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

和:

              LFMT (only) may contain:

       %L     contents of line

       %l     contents of line, excluding any trailing newline

       [...]

相关问题:https : //stackoverflow.com/questions/15384818/how-to-get-the-difference-only-additions-between-two-files-in-linux

在Ubuntu 18.04中测试。


-1

文件1:

text670_1
text067_1
text067_2

文件2:

text04_1
text04_2
text05_1
text05_2
text067_1
text067_2
text1000_1

采用:

diff -y file1 file2

这显示了对应文件的两列。

输出:

text670_1                           
                                  > text04_1
                                  > text04_2
                                  > text05_1
                                  > text05_2
text067_1                           text67_1
text067_2                           text67_2
                                  > text1000_1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.