2つのファイルを1行ずつ比較し、別のファイルに違いを生成する


120

file1とfile2を比較して、file2に存在しないfile1の行を含むfile3を生成します。


私はdiffを試しましたが、異なる行の前にいくつかの数字やその他の記号が生成され、ファイルの比較が困難になっています。

回答:


215

diff(1)は答えではありませんが、comm(1)はそうです。

NAME
       comm - compare two sorted files line by line

SYNOPSIS
       comm [OPTION]... FILE1 FILE2

...

       -1     suppress lines unique to FILE1

       -2     suppress lines unique to FILE2

       -3     suppress lines that appear in both files

そう

comm -2 -3 file1 file2 > file3

入力ファイルはソートする必要があります。そうでない場合は、最初に並べ替えます。これは一時ファイルで行うことができます、または...

comm -2 -3 <(sort file1) <(sort file2) > file3

シェルがプロセス置換をサポートしている場合(bashがサポート)。


1
2つのファイルは並べ替える必要があり、一意であることに注意してください
andy

6
一緒にグループ化できますオプション:comm -23
パオロM

「並べ替え」とはどういう意味ですか?行が同じ順序であること?次に、ほとんどのユースケースでおそらく問題ありません。たとえば、バックアップされた古いバージョンと比較して、どの行が追加されたかを確認します。新しく追加された行を既存の行の間に置くことができない場合、それはさらに問題になります。
Egor Hans

@EgorHans:ファイルに「3 \ n1 \ n3 \ n2 \ n」などの整数を含む行がある場合、最初に昇順または降順で並べ替える必要があります。たとえば、「\ 1 \ n2 \ n3 \ n3 \ n」は重複しています隣接。これは「ソート」されており、両方のファイルを同様の方法でソートする必要があります。新しいファイルに新しい行がある場合、それらが「既存の行の間」であるかどうかは関係ありません。なぜなら、並べ替え後は、それらが並べ替えられていないためです。
sorpigal

47

Unixユーティリティdiffは、まさにこの目的のためのものです。

$ diff -u file1 file2 > file3

オプションやさまざまな出力形式などについては、マニュアルとインターネットを参照してください。


7
それは要求された仕事をしません。他の回答で提案されているコマンドラインスイッチを使用しても、余分な文字がたくさん挿入されます。
xenocyon

20

これを考慮してください:
ファイルa.txt:

abcd
efgh

ファイルb.txt:

abcd

あなたは違いを見つけることができます:

diff -a --suppress-common-lines -y a.txt b.txt

出力は次のようになります。

efgh 

次を使用して、出力を出力ファイル(c.txt)に書き直すことができます。

diff -a --suppress-common-lines -y a.txt b.txt > c.txt

これはあなたの質問に答えます:

「... file1にはfile2に存在しない行が含まれています。」


2
この回答には2つの制限があります:(1)短い行(デフォルトでは80文字未満ですが、これは変更できます)でのみ機能し、さらに重要なのは、(2)それぞれの末尾に「<」を追加することです。別のプログラム(awk、sedなど)で削除する必要がある行。
sergut

多くの場合、あなたはまた、使用したいと思う-dようになりますこれは、diff可能な最小の差分を見つけるために最善を尽くし。-i-E-w-B--suppress-blank-emptyも限らないものの、時折役立ちます。ユースケースに何が当てはまるかわからない場合は、diff --help最初に試してください(コマンドで何ができるかわからない場合は、通常、これをお勧めします)。
Egor Hans

また、-line-format =%Lを使用すると、diffが余分な文字を生成しないようにします(少なくとも、ヘルプでは、このように機能しているが、試してみると述べています)。
エゴールハンス

また、これは短く、同じ作品らしいstackoverflow.com/a/27667185/1179925を
mrgloom

8

時には、diffあなたが必要なユーティリティですが、時にはjoinより適切です。ファイルは事前にソートする必要があります。または、bash、ksh、zshなどのプロセス置換をサポートするシェルを使用している場合は、オンザフライでソートできます。

join -v 1 <(sort file1) <(sort file2)

これでメダルがもらえるはず!それはまさに私が過去2時間探していたものでした
Zatarra

7

試す

sdiff file1 file2

通常は、ほとんどの場合、私にとってははるかにうまく機能します。行の順序が重要でない場合は、事前にファイルをソートすることをお勧めします(例:一部のテキスト構成ファイル)。

例えば、

sdiff -w 185 file1.cfg file2.cfg

1
素敵なユーティリティ!私はそれが差別化された線をどのようにマークするかが大好きです。設定の比較がはるかに簡単になります。並べ替えを持つこの一緒には致命的なコンボである(例えばsdiff <(sort file1) <(sort file2)
jmagnusson

3

あなたがcoreutilsでこれを解決する必要がある場合、受け入れられた答えは良いです:

comm -23 <(sort file1) <(sort file2) > file3

次のように、sd(ストリームdiff)を使用することもできます。これは、ソートやプロセス置換を必要とせず、無限ストリームをサポートします。

cat file1 | sd 'cat file2' > file3

おそらくこの例ではそれほどメリットはありませんが、それでも考慮してください。場合によっては使用できなくなりますcomm nor grep -Fもnor もdiff

これは、sdを紹介する、ターミナルでのストリームの差分について書いたブログ投稿です。


3

それでもgrep解決策はありませんか?

  • file2にのみ存在する行:

    grep -Fxvf file1 file2 > file3
  • file1にのみ存在する行:

    grep -Fxvf file2 file1 > file3
  • 両方のファイルに存在する行:

    grep -Fxf file1 file2 > file3

2

すでに多くの回答がありますが、どれもIMHOを完璧にするものではありません。Thanatosの回答では、1行あたりに余分な文字がいくつか残っています。Sorpigalの回答では、ファイルを並べ替えるか事前に並べ替える必要がありますが、すべての状況で適切とは限りません。

私は違うと何もしているライン(余分な文字、無並べ替え)を得るための最善の方法は、の組み合わせだと思うdiffgrepawk(または類似)。

行に「<」が含まれていない場合、短いワンライナーは次のようになります。

diff urls.txt* | grep "<" | sed 's/< //g'

しかし、これは "<"(スペース未満)のすべてのインスタンスを行から削除します。これは常に問題があるわけではありません(例:ソースコード)。最も安全なオプションは、awkを使用することです。

diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'

このワンライナーは両方のファイルを比較し、次にdiffのedスタイルの出力をフィルターで除外し、diffが追加する末尾の「<」を削除します。これは、行に「<」が含まれている場合でも機能します。


1
commはソートを必要としません(新しいバージョンでは?)---nocheck-orderを使用してください。私はこれをCLIからcsvsを操作するときによく使用します
ak5

2

たとえば、サイドバイサイドの出力diff -y生成することについてだれも言及しなかったことに驚いています。たとえば、

diff -y file1 file2 > file3

そしてfile3(別の線の|中央に記号があります):

same     same
diff_1 | diff_2


0
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt

私はこのスレッドでほとんどすべての答えを試しましたが、どれも完全ではありませんでした。上記のいくつかの道が私のために働いた後。diffは違いを与えますが、不要な特殊文字がいくつかあります。実際の差異行は '>'で始まります。したがって、次のステップは「>」で始まるgrep行であり、sedで同じ行を削除します。


1
これは悪い考えです。で始まる行も変更する必要があり<ます。入力ファイルの順序を入れ替えると、これがわかります。これを行ったとしても、grepより多くのsedを使用して省略したいでしょう: `diff a1 a2 | sedの「/> / sの///」 `これはまだ含む行破ることができる>か、<右の状況でをして、まだ行番号を記述した余分な行を残します。このアプローチを試したい場合、より良い方法は次のとおりdiff -C0 a1 a2 | sed -ne '/^[+-] /s/^..//p'です。
sorpigal

0

あなたは使うことができます diff次の出力フォーマットで。

diff --old-line-format='' --unchanged-line-format='' file1 file2

--old-line-format=''、行が異なる場合はfile1の出力を無効にし、file2で比較します。
--unchanged-line-format=''、行が同じ場合は出力を無効にします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.