web-dev-qa-db-ja.com

追加された行と削除された行のみを表示するようにdiffを取得するにはどうすればよいですか? diffがそれを実行できない場合、どのツールを使用できますか?

追加された行と削除された行のみを表示するようにdiffを取得するにはどうすればよいですか? diffがそれを実行できない場合、どのツールを使用できますか?

71
C. Ross

通信してみてください

それを見る別の方法:

  • ファイル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

ファイルが非常に長い場合、追加のコピーが必要になるため、ディスク容量が2倍になるため、これはかなりの負担になる可能性があります。

85
TomOnTime

comm はあなたが望むことをするかもしれません。そのmanページから:

説明

ソートされたファイルFILE1とFILE2を行ごとに比較します。

オプションなしで、3列の出力を生成します。 1列目にはFILE1に固有の行が含まれ、2列目にはFILE2に固有の行が含まれ、3列目には両方のファイルに共通の行が含まれています。

これらの列は、それぞれ-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

Manページにあるように、ファイルは事前にソートする必要があります。

15
markdrayton

コンテキストなしで追加と削除を表示するには、行番号+、-、<、>!など、次のようにdiffを使用できます。

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

たとえば、次の2つのファイルがあるとします。

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
10
iphonedroid

これがdiffがデフォルトで行うことです...おそらく、空白を無視するためにいくつかのフラグを追加する必要がありますか?

diff -b -B

空白行と異なる数のスペースは無視する必要があります。

2
Scott Lundberg

いいえ、実際にdiffは、2つのファイルの違いを実際の人が考えているように示しているわけではありません。あるファイルを別のファイルに変更するために使用するpatchなどのツールの一連の編集コマンドを生成します。

探していることを実行しようとする試みの難しさは、削除された行に続いて追加された行に対して、変更された行を構成するものを定義する方法です。また、線が隣接して追加、削除、および変更されたときに何をすべきか。

視覚的な比較ツールは2つのファイルを合わせて、行数は同じで内容が異なるセグメントが変更されたセグメントと見なされるようにします。一致するセグメント間の完全に新しい行は、追加されたセグメントと見なされます。

これはsdiffコマンドラインツールの動作方法でもあり、ターミナルで2つのファイルを並べて比較します。変更された行は|で区切られますキャラクター。行がファイルAにのみ存在する場合、<が区切り文字として使用されます。行がファイルBにのみ存在する場合、区切り文字として>が使用されます。ファイルに<と>の文字がない場合は、これを使用して、追加された行のみを表示できます。

sdiff A B | grep '[<>]'
2
Seppo Enarvi

Senarviに感謝します。あなたの解決策(投票されていません)は、実際に大量のページで年齢を探した後、まさに私が欲しかったものを与えてくれました。

あなたの答えを使用して、変更/追加/削除されたもののリストを取得するために私が思いついたのは次のとおりです。この例では、2つのバージョンの/ etc/passwdファイルを使用し、関連するレコードのユーザー名を出力します。

#!/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}'
2
geniosity

私はこの特定のフォームがしばしば役立つと思います:

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でテスト済み。