diff
これは、GNU出力の古い/新しい/変更されていない行のフォーマットを制御することで実現できます。
diff --new-line-format="" --unchanged-line-format="" file1 file2
これを機能させるには、入力ファイルをソートする必要があります。bash
(and ) を使用zsh
すると、プロセス置換でその場でソートできます<( )
。
diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2)
上記の新しい行と変更されていない行は抑制されているため、変更された行 (つまり、この場合は削除された行) のみが出力されます。diff
大文字と小文字を無視するなど、他のソリューションでは提供されないいくつかのオプションを使用することも、厳密でない一致のために-i
さまざまな空白オプション ( -E
、など) を使用することもできます。-b
-v
説明
オプション--new-line-format
と--old-line-format
を使用すると、フォーマット指定子と同様に、違いをフォーマット --unchanged-line-format
する方法を制御できます。これらのオプションは、新しい(追加された)、古い(削除された) 行、および変更されていない行をそれぞれフォーマットします。1 つを空の "" に設定すると、そのような行の出力が防止されます。diff
printf
統一された差分形式に精通している場合は、次の方法で部分的に再作成できます。
diff --old-line-format="-%L" --unchanged-line-format=" %L" \
--new-line-format="+%L" file1 file2
指定子は問題の%L
行であり、それぞれに「+」「-」または「」のような接頭辞を付けます(違いを出力するだけで、グループ化された各変更の上部にand行diff -u
がないことに注意してください)。これを使用して、各行に で番号を付けるなど、他の便利なことを行うこともできます。---
+++
@@
%dn
メソッドはdiff
(他の提案comm
およびとともに)ソートされたjoin
入力で期待される出力のみを生成しますが、その場でソートするために使用できます。これは、任意に順序付けられた入力ファイルを受け入れ、欠落している行を file1 で発生する順序で出力する単純な(nawk) スクリプト (Konsolebox の回答にリンクされているスクリプトに触発されたもの)です。<(sort ...)
awk
# output lines in file1 that are not in file2
BEGIN { FS="" } # preserve whitespace
(NR==FNR) { ll1[FNR]=$0; nl1=FNR; } # file1, index by lineno
(NR!=FNR) { ss2[$0]++; } # file2, index by string
END {
for (ll=1; ll<=nl1; ll++) if (!(ll1[ll] in ss2)) print ll1[ll]
}
これは、file1 の内容全体を行ごとに行番号のインデックス付き配列ll1[]
に格納し、file2 の内容全体を行ごとにインデックス付き連想配列に格納しss2[]
ます。両方のファイルが読み取られた後、反復しll1
て演算子を使用してin
、file1 の行が file2 に存在するかどうかを判断します。diff
(重複がある場合、メソッドへの出力が異なります。)
ファイルが十分に大きく、両方を格納するとメモリの問題が発生する場合は、file1 のみを格納し、file2 が読み取られる途中で一致を削除することにより、CPU をメモリと交換できます。
BEGIN { FS="" }
(NR==FNR) { # file1, index by lineno and string
ll1[FNR]=$0; ss1[$0]=FNR; nl1=FNR;
}
(NR!=FNR) { # file2
if ($0 in ss1) { delete ll1[ss1[$0]]; delete ss1[$0]; }
}
END {
for (ll=1; ll<=nl1; ll++) if (ll in ll1) print ll1[ll]
}
上記は file1 の内容全体を 2 つの配列に格納します。1 つは行番号ll1[]
でインデックス付けされ、もう 1 つは行コンテンツでインデックス付けされますss1[]
。次に、file2 が読み取られると、一致する各行が および から削除されll1[]
ますss1[]
。最後に、file1 の残りの行が出力され、元の順序が維持されます。
この場合、前述の問題により、GNU (フィルタリングは GNU 拡張機能です) を使用して分割して征服split
し、file1 のチャンクを使用して繰り返し実行し、毎回 file2 を完全に読み取ることもできます。
split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1
コマンドラインでの-
意味stdin
の使用と配置に注意してください。gawk
これは、split
呼び出しごとに 20000 行のチャンクで from file1 によって提供されます。
GNU 以外のシステムのユーザーの場合、GNU バージョンではなくPOSIX/BSD のみですが、 GNUを提供するApple Xcodeツールの一部として OSX を含め、ほぼ確実に入手できる GNU coreutils パッケージがあります。diff
awk
split