ファイル内の重複行を楽に探すunixコマンド
先日、大量のデータから完全に重複した行を探す処理をする機会があった。そのときはどうすればいいか手間取ってしまったが、コマンドを工夫すればすぐにできる内容だった。
以下の単純なサンプルログtest.txt
を例に取る。
{"location_name": "title", "timestamp_micros": 1531209434523235} {"location_name": "product1", "timestamp_micros": 1531209437623412} {"location_name": "product1", "timestamp_micros": 1531209437623412} {"location_name": "title", "timestamp_micros": 1531209456903712}
たった4行なのですぐわかるが、2行目と3行目が重複している。これをコマンドで抽出したい。 このとき、以下のようなコマンドを使うと、重複行の内容とその頻度がすぐわかる。
$ uniq -c test.txt | sort -n -k 1 -r 2 {"location_name": "product1", "timestamp_micros": 1531209437623412} 1 {"location_name": "title", "timestamp_micros": 1531209456903712} 1 {"location_name": "title", "timestamp_micros": 1531209434523235}
コマンドを分解してひとつずつ見てみる。
uniqコマンド
uniqコマンドは、ファイル内から重複する行を削除して標準出力する。
$ uniq test.txt {"location_name": "title", "timestamp_micros": 1531209434523235} {"location_name": "product1", "timestamp_micros": 1531209437623412} {"location_name": "title", "timestamp_micros": 1531209456903712}
重複行が消えて3行になって出力された。
注意すべきなのが、重複行が隣り合っていないと検知できないこと。使う前に行のソートが必要になることが多い。
ただし今回はアクセスログだったのでtimestamp_micro順に並んでおり、事前のソートは必要なかった。
また、uniqコマンドの便利なオプションが-c
。
重複行が消えずに、重複した内容とその行数も表示してくれる。
$ uniq -c test.txt 1 {"location_name": "title", "timestamp_micros": 1531209434523235} 2 {"location_name": "product1", "timestamp_micros": 1531209437623412} 1 {"location_name": "title", "timestamp_micros": 1531209456903712}
sortコマンド
行をソートできるコマンド。
-n
は数値として並べ替えをするオプション。これをつけないと文字コード上の順になるため、10が2より前になったりしてしまう。
-k
は空白区切りやカンマ区切りのデータのとき、並べ替えの基準となるキーを指定するもの。
-r
はソート結果を降順に出力するもの。
ポイントになるのが-k
の使い方。
上のuniq -c
コマンドの出力を見ると、実データの前に重複した数が表示されている。しかもこの数と実データの間にはスペースが空いている。
つまりこの出力をパイプで受け渡し、-k 1
とすれば、1番目のキーとして重複した数をソートに使うことができる。これがuniq -c test.txt | sort -n -k 1 -r
の意味だ。
もっとも今回はソートのキーが一番最初のものなので、-n
さえつけていれば-k
はつけなくても良いのだが、このオプションを知っておくと便利なことが多いだろう。
ちなみに-k
の数値が2〜4の場合は、データが数値ではないので並べ替えは起こらないが、5にするとtimestamp_microsの値でソートされる。5というのはデータをスペース区切りとみなしたときに5番目ということ。
調べているうちに、コマンドの本を昔読んだ記憶がよみがえってきた。やっぱり使わないと覚えられない。