2つの大きなファイルの違い


14

「test1.csv」があります

200,400,600,800
100,300,500,700
50,25,125,310

およびtest2.csvとそれが含まれています

100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5

diff test2.csv test1.csv > result.csv

とは異なります

diff test1.csv test2.csv > result.csv

どちらが正しい順序かわかりませんが、何か他のものが必要です。上記のコマンドは両方とも次のようなものを出力します

2 > 100,4,2,1,7
   3 2,3c3,5
   4 < 100,300,500,700
   5 < 50,25,125,310
   6 \ No newline at end of file
   7 ---
   8 > 21,22,23,24,25
   9 > 50,25,125,310

差のみを出力したいので、results.csvは次のようになります。

100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

私が試したdiff -qし、diff -s彼らはトリックをしませんでした。順序は関係ありません。重要なのは、違いだけを見たいということです。

grep -FvF 大きなファイルではなく小さなファイルでトリックを行いました

最初のファイルには500万行以上が含まれ、2番目のファイルには1300行が含まれています。

そのため、results.csvは〜4,998,700行になるはずです。

私も試してみましたgrep -F -x -v -f が、うまくいきませんでした。



1
@Tim私はあなたのリンクを見て、私は古いメンバーですので、ルールを知っていますが、不注意でした、申し訳ありません:)それを編集していて、投稿が編集されたというポップアップが表示されたので、あなたは私のために仕事をしました感謝します
リノブ

50,25,125,310両方のファイルに共通です。目的の出力から削除する必要があります。
heemayl

順序を保持する必要がありますか?
コス

1
情報をどのように処理するかによって異なります。diff、IMOは、パッチを作成するためのものです。とにかく、私はあなたの最高のツール、diff、grep、awk、またはperlを確信しています。
パンサー

回答:


20

の仕事のように聞こえcommます:

$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
    100,4,2,1,7
    21,22,23,24,25
    50,25,700,5

で説明されているようにman comm

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

したがって、-3ファイルの1つに固有の行のみが印刷されることを意味します。ただし、それらは見つかったファイルに応じてインデントされます。タブを削除するには、次を使用します。

$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

この場合、ファイルをソートする必要さえありません。上記を単純化して次のことができます。

comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv

200,[...]行の後のスペースにだまされていませんか?:)
コス

@kosいいえ、最初にファイルから末尾のスペースを削除しました。OPのファイルには実際にはファイルがないと想定しました。
テルドン

6

使用grepしてbashプロセス置換:

$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

出力を次のように保存するにはresults.csv

cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
  • <()あるbashプロセスの置換パターンは、

  • grep -vFf test2.csv test1.csv のみに固有の行が見つかります test1.csv

  • grep -vFf test1.csv test2.csv のみに固有の行が見つかります test2.csv

  • 最後に、結果を要約します。 cat

または、Oliが提案したように、コマンドのグループ化も使用できます。

$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

または、次から次へと実行します。どちらもSTDOUTに書き込みを行っているため、最終的に追加されます。

$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

1
なぜcat2つのリダイレクトされたコマンドですか?なぜ一方を実行してから他方を実行しないのですか?grep ... ; grep ...または{ grep ... ; grep ... ; }、集合出力で何かをしたい場合。
オリ

@Oli Thanks..thats偉大idea..iは...そのことを考えていなかった
heemayl

4

行の順序が関係ない場合は、awkまたはを使用しますperl

awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv

を使用grepして、共通の行を取得し、それらを除外します。

grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv

内部grepは共通行を取得し、外部grepはこれらの共通行と一致しない行を見つけます。


awkコマンドは再実装するだけでsort | uniq -u、1つのファイルに重複する行が含まれていると間違った答えが返されます。grepについては、「内部」/「外部」ではなく、「内部」/「外部」と言います。
ピーター

@PeterCordesはい、そうです、あなたはそれが間違った結果だと言うのは誰ですか?
ムル

そのコーナーケースでは、質問がまさに求めていたものではないという意味で間違っています。それは誰かが欲しいものかもしれませんが、あなたはあなたがどのような違いを指摘しておきawk、印刷し、何comm -3diff答えが印刷されます。
ピーターコーデス

@PeterCordes再び、あなたは誰と言っていますか?OPがそれを望んでいると言うまで、出力がの出力と異なるかどうかは気にしませんcomm -3。なぜ私はいかなる理由が表示されない、私はそれを説明する必要があります。メモを編集する場合は、お気軽に。
ムル

OPは、彼が違いを望んでいると言いました。それは常にあなたのプログラムが生成するものではありません。1つのテストケースに対して同じ出力を生成しますが、すべてのケースについて記述された説明を満たさないプログラムには、注意が必要です。私はそれを言うためにここにいます、そして、それは私が誰であるかあなたが誰であるかに関係なく真実です。メモを追加しました。
ピーター

4

以下の--*-line-format=...オプションを使用しますdiff

diff必要なものを正確に伝えることができます-以下で説明します:

diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' f1.txt f2.txt

printf数値形式と同様に、非常に詳細な方法でdiffの出力を指定することができます。

最初のファイルの行test1.csvは「古い」行と呼ばれ、2番目の行はtest2.csvは「新しい」行です。diffファイル内の変更を確認するために使用される場合、それは理にかなっています。

必要なオプションは、「古い」行、「新しい」行、および「変更されていない」行のフォーマットを設定するためのものです。
必要な形式は非常に単純です。
新しい行と古い行の変更については、行のテキストのみを出力する必要があります。%Lは、行テキストのフォーマット記号です。
変更されていない行については、何も表示しません。

これにより--old-line-format='%L'、サンプルデータを使用して、などのオプションを記述し、すべてをまとめることができます。

$ diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' test1.csv test2.csv
100,4,2,1,7
100,300,500,700
21,22,23,24,25
50,25,700,5


パフォーマンスに関する注意

ファイルのサイズは異なるため、重要でない場合は入力ファイルを交換してみてください。 diff一方よりも他方をうまく処理できる可能。より良いのは、必要なメモリが少ないか、計算が少ないことです。

diff大きなファイルで使用するための最適化オプションがあります--speed-large-files。ファイル構造に関する仮定を使用しているので、あなたの場合に役立つかどうかは明らかではありませんが、試してみる価値があります。

フォーマットオプションについては、man diff下で説明します--LTYPE-line-format=LFMT


3

順序を保持する必要はないので、単純に:

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csv:マージおよびソートtest1.csvtest2.csv
  • uniq -u:重複のない行のみを出力します

1つのファイルに行が2回含まれていて、他のファイルには表示されない場合、これは機能しません。両方のdiff結果が結果になります。
フォルカーシーゲル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.