先日、大量のデータから完全に重複した行を探す処理をする機会があった。そのときはどうすればいいか手間取ってしまったが、コマンドを工夫すればすぐにできる内容だった。
以下の単純なサンプルログ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番目ということ。
調べているうちに、コマンドの本を昔読んだ記憶がよみがえってきた。やっぱり使わないと覚えられない。