sort と uniq の使い方 - データを並べ替えて重複を削る

sort と uniq の使い方 - データを並べ替えて重複を削る

この記事で学べること

  • sort行を並べ替える 基本操作(辞書順・数値順・逆順)が分かる
  • uniq重複行を削る 使い方と「sort が前提」という暗黙のルールが分かる
  • sort | uniq -c | sort -rn という 頻度ランキングの定番形 が書けるようになる
  • 初心者がハマりやすい uniq だけ使うと消えない」「数字が変な順に並ぶ」 の理由が腑に落ちる

結論(先に覚える型)

  • 並べ替えたい → sort
  • 並べ替え+重複を消したい → sort -u
  • 「何が何回出たか」を集計したい → sort | uniq -c | sort -rn

前提(対象環境)

  • OS:Ubuntu / 一般的な Linux
  • GNU coreutils の sort / uniq(macOS の BSD 版と細部の挙動が異なるオプションあり)

1. まずはここから:行を「並べ替える」とは

リナ: 先輩、ログとかリストを「アルファベット順に並べ替えたい」ってよくありますよね。あれってどうやるんですか?
ライニー先輩: そういうときの基本コマンドが sort だよ。sort ファイル名1 行ずつ並べ替えて表示 してくれる。中身を書き換えるんじゃなくて、画面に並べ替えた結果を出してくれるだけだから、間違えても元のファイルは壊れない。
リナ: 元ファイルは触らないんですね。安心。
ライニー先輩: そう。そして並べ替えには 辞書順・数値順・逆順 の3種類があって、これだけ覚えれば 8 割は対応できる。

サンプルとして次のファイルを用意しよう。

$ cat fruits.txt
banana
apple
cherry
apple
banana
date

1-1. 基本:辞書順に並べ替える

$ sort fruits.txt
apple
apple
banana
banana
cherry
date

ポイント

  • sortデフォルトで辞書順(アルファベット順)
  • 大文字・小文字は通常別物として扱われる(大文字が先になる)
  • 元のファイルは 変わらない(並べ替え結果を画面に出すだけ)

1-2. 逆順(降順)に並べ替える -r

$ sort -r fruits.txt
date
cherry
banana
banana
apple
apple

-rreverse(逆)の頭文字。

2. 数値の並べ替えで初心者がハマる罠

リナ: 数字を並べ替えたら、なんか順番が変です...
ライニー先輩: ちょうどいい例だね。実際に見てみよう。
$ cat scores.txt
100
3
25
9
1000
$ sort scores.txt
100
1000
25
3
9
リナ: えっ、10025 より先に来てるし、39 が最後に来てます。バグですか?
ライニー先輩: バグじゃないんだ。sort のデフォルトは 「文字列として1文字ずつ左から比較」 するから、1 で始まる行が 23 で始まる行より前に並んでしまう。数値として並べ替えたいなら -n を付けるんだ。

2-1. 数値ソート -n

$ sort -n scores.txt
3
9
25
100
1000

-nnumeric(数値)の頭文字。

初心者あるある

  • ログのサイズや件数を並べたいとき -n を忘れて変な順序になる
  • 「数字っぽい列なら全部 -n を付ける」と覚えておくと事故が減る

2-2. 数値の大きい順(降順)

$ sort -nr scores.txt
1000
100
25
9
3

-n-r組み合わせ可能。ランキング系の処理で頻出する形。

3. 並べ替え+重複削除 sort -u

$ sort -u fruits.txt
apple
banana
cherry
date
リナ: あれ、applebanana が 1 行ずつになりました。
ライニー先輩: そう。-uunique(一意)の頭文字で、sort 結果から重複行を取り除いてくれるオプション。「並べ替えてユニークにしたい」なら これ一発で済む

実務では「ユニークな値の一覧が欲しい」場面が圧倒的に多い。sort -u を覚えておくと早い。

4. uniq:重複を削る専門コマンド

4-1. 基本

$ uniq fruits.txt
banana
apple
cherry
apple
banana
date
リナ: あれっ、applebanana もまだ重複してるじゃないですか...
ライニー先輩: 実はここが uniq最大の落とし穴 なんだ。uniq「連続している重複だけ」 を削る。離れた場所にある重複は消してくれない。
リナ: えっ、じゃあどうすれば...
ライニー先輩: そのために先に sort する。sort で同じ行を 隣り合わせ にしてから uniq に渡せば、ちゃんと重複が消える。

4-2. sort | uniq の組み合わせ

$ sort fruits.txt | uniq
apple
banana
cherry
date

鉄則

  • uniq必ず sort の後ろに置く
  • 単独で使うのは「すでに並んでいると分かっているとき」だけ
  • 「並べてユニーク」だけが目的なら sort -u の方が短い

4-3. 各行が何回出たかを数える uniq -c

$ sort fruits.txt | uniq -c
      2 apple
      2 banana
      1 cherry
      1 date

-ccount。行頭に 出現回数 が付く。集計に超便利。

4-4. 重複している行だけ・1 回だけの行だけ

# 重複している行だけ表示
$ sort fruits.txt | uniq -d
apple
banana
# 1 回しか出ていない行だけ表示
$ sort fruits.txt | uniq -u
cherry
date
オプション 意味 用途
-c カウント付与 集計
-d 重複行だけ 重複している項目を洗い出す
-u ユニーク行だけ 1 回しか出ない行を抽出
-i 大文字小文字無視 表記ゆれをまとめる

5. 実務でいちばん使う型:頻度ランキング

リナ: アクセスログとかで「どの IP からのアクセスが多いか」を出したいんですけど、どうやれば...
ライニー先輩: それが今日のクライマックス。sort | uniq -c | sort -rn という 3 段パイプ が定番。これは丸暗記していい。

サンプルログ:

$ cat access.log
192.168.1.10
192.168.1.20
192.168.1.10
192.168.1.30
192.168.1.10
192.168.1.20

頻度ランキング:

$ sort access.log | uniq -c | sort -rn
      3 192.168.1.10
      2 192.168.1.20
      1 192.168.1.30

3 段パイプの分解

コマンド やっていること
1 sort 同じ行を隣り合わせにする
2 uniq -c 隣り合った重複をまとめてカウント付き
3 sort -rn カウント(数値)の大きい順に並べる

5-1. 上位 N 件だけ欲しい

$ sort access.log | uniq -c | sort -rn | head -n 3

head -n 3上位 3 件 に絞る。head と組み合わせるのが現場の定番。

6. キー指定(応用):特定の列で並べ替える -k

CSV やスペース区切りのデータでは、-k何列目で並べ替えるか を指定できる。

$ cat sales.txt
apple 120
banana 80
cherry 200
date 50
# 2 列目(数値)で降順に並べ替える
$ sort -k2 -nr sales.txt
cherry 200
apple 120
banana 80
date 50
  • -k2 で 2 列目を基準にする
  • 数値列なら -n を忘れずに
  • 区切り文字を変えたい場合は -t,(カンマ区切り)など

7. よくある初心者のつまずき

7-1. uniq を使ったのに重複が消えない

原因sort していない。

# NG: 連続していない重複は消えない
$ uniq fruits.txt

# OK
$ sort fruits.txt | uniq
$ sort -u fruits.txt

7-2. 数字が変な順に並ぶ

原因-n を付けていない。文字列比較になっている。

$ sort -n scores.txt   # 数値として並べる

7-3. 元ファイルが書き換わらない

sort画面に結果を出すだけ で元ファイルは変えない。書き換えたい場合は 明示的にリダイレクトする

$ sort fruits.txt > fruits-sorted.txt

やってはいけないこと

# NG: ファイルが空になる
$ sort fruits.txt > fruits.txt

>コマンド実行前にファイルを空にする ため、sort が読む前に中身が消える。同じファイルに上書きしたい場合は別ファイルに出してから差し替えるか、sort -o を使う:

# OK: -o は読み終わってから書き込む
$ sort -o fruits.txt fruits.txt

7-4. 大文字・小文字が別物扱いされる

$ cat names.txt
Alice
bob
Alice
BOB
$ sort -u names.txt
Alice
BOB
bob

大文字小文字を区別したくない場合は -ffold case):

$ sort -uf names.txt
Alice
bob

8. ミニ課題:実際にやってみよう

リナ: 知識は入りました! 手を動かして確かめたいです。
ライニー先輩: いいね、3 問用意したよ。ターミナルで試してみて。

課題 1:次のファイルからユニークな単語の一覧を出そう。

$ cat << 'EOF' > words.txt
apple
banana
apple
cherry
banana
EOF
ヒントを見る

「並べ替え+重複削除」一発でできるオプションがあったはず。

解答例
$ sort -u words.txt
apple
banana
cherry

課題 2:上のファイルから 各単語が何回出たか を集計しよう。

ヒントを見る

sortuniq -c の 2 段パイプ。

解答例
$ sort words.txt | uniq -c
      2 apple
      2 banana
      1 cherry

課題 3:上の集計結果を 多い順(降順) に並べ替えて、上位 2 件だけ表示しよう。

ヒントを見る

カウント列を数値として降順に並べる → head で 2 件。

解答例
$ sort words.txt | uniq -c | sort -rn | head -n 2
      2 apple
      2 banana

9. コピペ用テンプレート

よく使う型をまとめておく

# 並べ替え(辞書順)
sort file.txt

# 並べ替え+重複削除
sort -u file.txt

# 数値として並べ替え(昇順 / 降順)
sort -n file.txt
sort -nr file.txt

# 重複行のカウント
sort file.txt | uniq -c

# 頻度ランキング(多い順)
sort file.txt | uniq -c | sort -rn

# 頻度ランキング上位 10 件
sort file.txt | uniq -c | sort -rn | head -n 10

# 2 列目で降順
sort -k2 -nr file.txt

# 大文字小文字を無視してユニーク化
sort -uf file.txt

# 元ファイルにそのまま書き戻す(事故防止: -o を使う)
sort -o file.txt file.txt

まとめ:次に読む