web-dev-qa-db-ja.com

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

「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 -qdiff -sを試しましたが、彼らはトリックをしませんでした。順序は関係ありません。重要なのは、違いだけを見たいということです。

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

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

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

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

14
Lynob

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
20
terdon

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
6
heemayl

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

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 で説明しています。

4
Volker Siegel

行の順序が関係ない場合は、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はこれらの共通行と一致しない行を検出します。

4
muru

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

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csvtest1.csvtest2.csvのマージと並べ替え
  • uniq -u:重複のない行のみを出力します
3
kos