0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

テキストファイル内の重複行をソートせずに削除

Posted at

テキストファイルの重複行を削除する際、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 回目以降の重複が無視される。(最後だけ前置インクリメントにしているのはその方が主観的に分かりやすく感じたため)

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?