テキストファイルの重複行を削除する際、sort tmp.txt | uniq
だと当然ソートされてしまう。
ソートせずに順番は保ったまま重複行を削除したい場合は awk を利用すると楽。
基本の形は awk '!a[$0]++ {print}'
!a[$0]++ の部分を変えることで一部が重複している行を対象にしたり、重複回数で絞れたりできる。
# 重複行削除
cat tmp.txt | awk '!a[$0]++ {print}'
# 重複している行のみ出力
cat tmp.txt | awk 'a[$0]++ == 1 {print}'
# 2 列目が重複している行を削除
cat tmp.txt | awk '!a[$2]++ {print}'
# 3 回目以降の重複は削除
cat tmp.txt | awk '++a[$0] < 3 {print}'
動作
$ cat tmp.txt
hoge 100
fuga 200
foo 200
foo 200
foo 200
foo 200
fuga 200
foo 200
$ cat tmp.txt | awk '!a[$0]++ {print}'
hoge 100
fuga 200
foo 200
$ cat tmp.txt | awk 'a[$0]++ == 1 {print}'
foo 200
fuga 200
$ cat tmp.txt | awk '!a[$2]++ {print}'
hoge 100
fuga 200
$ cat tmp.txt | awk '++a[$0] < 3 {print}'
hoge 100
fuga 200
foo 200
foo 200
fuga 200
解説
!a[$0]++
の部分について、\$0 (行全体) の値が初出の場合は a[\$0] = 0 となる。
awk では 0 は false 扱いされるので結果として !a[$0] == !0 == true
となり出力される。
2 回目以降は後置インクリメントされているので a[\$0] = 1, a[\$0] = 2... となり、0 以外の数字は true 扱いされるので !a[$0] == !X == false
(X は 1 以上の整数) となり無視される。
なので a[$0]++ == 1
とすれば 2 回目に出現した行のみ true となるし、!a[$2]++
とすれば 2 列目だけを見て重複判定するし、++a[$0] < 3
とすれば 3 回目以降の重複が無視される。(最後だけ前置インクリメントにしているのはその方が主観的に分かりやすく感じたため)