Linux/Shell envで作業して、次のことをどのように達成できますか?
テキストファイル1に含まれるもの:
1
2
3
4
5
テキストファイル2に含まれるもの:
6
7
1
2
3
4
ファイル1にはないファイル2のエントリを抽出する必要があります。この例では、「6」と「7」です。
コマンドラインからこれを行うにはどうすればよいですか?
どうもありがとう!
$ awk 'FNR==NR {a[$0]++; next} !a[$0]' file1 file2
6
7
コードの仕組みの説明:
詳細の説明:
FNR
は現在のファイルのレコード番号ですNR
は、すべての入力ファイルの現在の全体的なレコード番号ですFNR==NR
は、file1を読み取っているときにのみtrueです$0
は現在のテキスト行ですa[$0]
は、現在のテキスト行にキーが設定されたハッシュですa[$0]++
現在のテキスト行を見たトラック!a[$0]
は、行テキストが表示されていない場合にのみtrueですあまり知られていないユーティリティを使用する:
sort file1 > file1.sorted
sort file2 > file2.sorted
comm -1 -3 file1.sorted file2.sorted
これは重複を出力するので、1がある場合は3
in file1
、ただし2でfile2
、これでも1を出力します3
。これが適切でない場合は、sort
からuniq
までの出力をパイプしてから、ファイルに書き込みます。
sort file1 | uniq > file1.sorted
sort file2 | uniq > file2.sorted
comm -1 -3 file1.sorted file2.sorted
GNU coreutilsパッケージには、あらゆる種類のテキスト操作を可能にする多くのユーティリティがあります。
次の解決策のどれが「大きい」ファイルの「最速」だったのかと思っていました。
awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2 # awk1 by SiegeX
awk 'FNR==NR{a[$0]++;next}!($0 in a)' file1 file2 # awk2 by ghostdog74
comm -13 <(sort file1) <(sort file2)
join -v 2 <(sort file1) <(sort file2)
grep -v -F -x -f file1 file2
要するに私のベンチマークの結果:
grep -Fxf
は使用しないでください。非常に遅くなります(テストでは2〜4回)。comm
はjoin
よりもわずかに高速です。comm
とjoin
はawk1 + awk2よりもはるかに高速です。 (もちろん、それらはソートされたファイルを想定していません。)comm
の実際の実行時間は、より多くのスレッドを使用するという事実が原因であると考えられます。CPU時間はawk1 + awk2。簡潔にするため、詳細は省略します。ただし、興味のある方は私に連絡したり、テストを繰り返したりできると思います。おおよその設定は
# Debian Squeeze, Bash 4.1.5, LC_ALL=C, slow 4 core CPU
$ wc file1 file2
321599 321599 8098710 file1
321603 321603 8098794 file2
最速の実行の典型的な結果
awk2: real 0m1.145s user 0m1.088s sys 0m0.056s user+sys 1.144
awk1: real 0m1.369s user 0m1.324s sys 0m0.044s user+sys 1.368
comm: real 0m0.980s user 0m1.608s sys 0m0.184s user+sys 1.792
join: real 0m1.080s user 0m1.756s sys 0m0.140s user+sys 1.896
grep: real 0m4.005s user 0m3.844s sys 0m0.160s user+sys 4.004
ところで、awkiesの場合:a[$0]=1
はa[$0]++
よりも高速で、(!($0 in a))
は(!a[$0])
よりも高速であるようです。したがって、awkソリューションについては、次のことをお勧めします。
awk 'FNR==NR{a[$0]=1;next}!($0 in a)' file1 file2
grep:
grep -F -x -v -f file_1 file_2
どうですか:
diff file_1 file_2 | grep '^>' | cut -c 3-
これにより、file_1にないエントリがfile_2に出力されます。反対の結果を得るには、 '>'を '<'に置き換える必要があります。 'cut'は、 'diff'によって追加された、元のコンテンツの一部ではない最初の2文字を削除します。
ファイルはソートする必要さえありません。
ここに別のawkソリューションがあります
$ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2
6
7
コマンドラインからこれを行うことにreallyを設定している場合、 this site (「重複は見つかりませんでした」を検索)には重複を検索するawk
の例。それを見るのは良い出発点かもしれません。
ただし、PerlまたはPython=を使用することをお勧めします。基本的に、プログラムのフローは次のようになります。
findUniqueValues(file1, file2){
contents1 = array of values from file1
contents2 = array of values from file2
foreach(value2 in contents2){
found=false
foreach(value1 in contents1){
if (value2 == value1) found=true
}
if(!found) print value2
}
}
O(n ^ 2)時間の複雑さがあるため、これはこれを行う最もエレガントな方法ではありませんが、うまく機能します。