これは、GNU diff
出力のold / new / unchanged行のフォーマットを制御することで実現できます。
diff --new-line-format="" --unchanged-line-format="" file1 file2
これを機能させるには、入力ファイルをソートする必要があります。bash
(と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
方法を制御diff
でき printf
ます。これらのオプションは、それぞれ新しい(追加された)、古い(削除された)、および変更されていない行をフォーマットします。1を空の ""に設定すると、そのような行の出力が防止されます。
統一されたdiff形式に慣れている場合は、次のようにして部分的に再作成できます。
diff --old-line-format="-%L" --unchanged-line-format=" %L" \
--new-line-format="+%L" file1 file2
%L
指定子は問題の行である、と私たちは「+」「でそれぞれの接頭辞-のように、」または「」diff -u
(それが唯一の出力の違いは、それが欠けていることに注意---
+++
して@@
、各グループ化された変更の先頭に行を)。これを使用して、各行にで番号を付けるなど、他の便利なこともでき%dn
ます。
このdiff
メソッドは、他の提案comm
やjoin
とともに、ソートされた入力で期待される出力のみを生成しますが<(sort ...)
、所定の位置でソートするために使用できます。ここでは簡単ですawk
(nawkの)スクリプト(スクリプトに触発さは、リンク先のKonsoleboxの答えで)任意の入力ファイルを命じ受け入れる、と彼らはFILE1に発生順に不足している行を出力します。
# 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のコンテンツ全体を行番号のインデックス配列に1行ずつ格納しll1[]
、file2のコンテンツ全体を行コンテンツのインデックス付き連想配列に1行ずつ格納し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
file1から、呼び出しごとに20000行のチャンクで提供されます。
非GNUシステム上のユーザーの場合、ほぼ確実に存在しているのGNU coreutilsのがの一部としてOSXに含め、あなたが得ることができ、パッケージのApple Xcodeの GNUツールを提供しdiff
、awk
けれども唯一のPOSIX / BSD split
ではなくGNUバージョン。
awk 'NR==FNR{a[$0];next}!($0 in a)' file2 file1 > out.txt