Linuxでテキストファイルの重複行を削除する方法とその応用

Linuxで重複行を取り除く方法は、「並び順を変えてよいか」で選びます。sort file | uniqは全体を並べ替えてから隣接重複をまとめる方法で、sort -uなら一度に行えます。元の出現順を保ちたいなら、awkの連想配列で最初の1行だけを出す方法がよく使われます。どの方法も、空白や大文字小文字が違う行を同じとみなすか、ロケール、巨大ファイルの容量、原本保全を先に決めてください。原本と同じファイルへ直接リダイレクトしてはいけません。

目次

uniqは隣接する重複だけをまとめる

uniqは入力の隣り合う同一行を1行へまとめます。ファイル全体から同じ行を探してくれるわけではありません。次のようにalpha、beta、alphaと離れて現れる場合、単独のuniqでは最後のalphaを削除しません。これは不具合ではなく仕様です。

printf '%s\n' alpha beta alpha | uniq

既にキー順に並んだ集計結果や、同じ値が連続するログならuniq単独で使えます。入力が本当に整列済みか、どの照合規則で並べたかを確認します。別のロケールや別キーで並べたデータにuniqを使うと、期待した重複が隣接しないことがあります。

全体の重複を除くsort -u

行の順番を変えてよい場合はsort -uが簡潔です。並べ替えと一意化を同じ照合規則で行います。結果は新しいファイルへ保存し、入力と同じパスを指定しません。シェルはsortが読み始める前に出力先を空にする可能性があるため、同じファイルへの>は原本消失につながります。

sort -u -- input.txt > unique-sorted-20260716.txt

出力ファイルが既に存在しないこと、保存先容量が十分なこと、umaskと権限が適切なことを実行前に確認します。sortは大きな入力で一時ファイルを使うため、出力先だけでなく一時領域にも空きが必要です。ネットワークストレージ上の巨大ファイルではI/O負荷を監視し、メンテナンス時間や担当者の承認を得ます。

sort | uniqとの違い

sort file | uniqも重複除去になります。uniqの-cで件数、-dで重複した値だけ、-uで一度だけ現れた値だけを出すなど、後段の集計機能を使いたいときに便利です。ただしパイプラインではsortの失敗を末尾のuniqが隠す可能性があるため、Bashのpipefailまたは各段の終了状態を確認します。単純な一意化ならsort -uの方が一工程で表現できます。

set -o pipefail
sort -- input.txt | uniq -c > line-counts-20260716.txt
status=$?
printf 'pipeline status=%s\n' "$status"

件数付き出力は先頭に数字と空白が加わるため、元データと同じ形式ではありません。後で機械処理する場合、区切りを空白だけで解析すると、元行の先頭空白と区別しにくいことがあります。入力形式に応じた構造化データ処理を検討します。

元の順番を保つawk

最初に出た行を残し、2回目以降を省くには、awkの連想配列を使います。seen[$0]を行全体をキーにし、未出現のときだけ出力します。結果は入力順を保ちます。

awk '!seen[$0]++' input.txt > unique-stable-20260716.txt

この方法は異なる一意行をメモリへ保持します。数千万のほぼ全部異なる行では、メモリ不足やスワップでサーバーへ大きな負荷をかける可能性があります。巨大データは、外部ソートを使う、データベースや専用処理基盤へ移す、分割キーを設計するなど別手段を検討します。またawk実装によって利用可能メモリや性能が異なります。

「同じ行」の定義を決める

バイト列が完全一致する行だけを重複とするのか、前後空白、連続空白、大文字小文字、全角半角、Unicode正規化、CRLF末尾を無視するのかを決めます。安易に正規化すると、本来異なるID、パス、パスワードハッシュ、製品コードを同じものとして失う危険があります。最初は完全一致を基準にし、業務要件が明確な場合だけ比較キーを加工します。出力は元の行を残すか、正規化済みの値を出すかも別の判断です。

大文字小文字を無視する例の注意

awkでtolower($0)をキーにすれば大小を無視できますが、どちらの表記を残すかは最初の出現順で決まります。ロケールとUnicodeの大小変換も影響します。アカウント名やファイルパスが大小を区別するシステムでは使いません。

awk '{ key=tolower($0); if (!seen[key]++) print }' input.txt > unique-casefolded-20260716.txt

前後空白を無視する前に

設定ファイルや固定幅データでは空白が意味を持ちます。uniq -fや-sでフィールドや文字を飛ばす、sortのキー指定を使う方法もありますが、sortとuniqで同じ比較範囲を使わないと結果が不整合になります。タブと空白、ロケール依存の空白文字、引用符内の空白も区別します。CSVならawkの単純な空白分割ではなくCSVパーサーを使います。

空行の扱い

完全一致の重複除去では、複数の空行も1行へまとまります。空行が段落区切りとして意味を持つ文書では、文書構造が壊れます。逆に、空行をすべて除きたい要件は「重複除去」ではなくフィルター処理です。最初の空行を残す、連続空行だけ1行へする、すべて除く、空白だけの行も空行とみなすという選択を明確にします。uniqは連続空行だけをまとめるので、文章の段落整形にはその性質が合う場合があります。

ロケールでsort順が変わる

sortの照合順序はLC_COLLATEなどのロケールに影響されます。Cロケールはバイト値に近い再現可能な順序に使われることがありますが、利用者が期待する日本語順とは異なります。LC_ALL=C sort -uを無条件に推奨せず、必要なのがバイト完全一致の再現性か、言語的な並びかを決めます。実行ロケール、sort版、オプションを処理記録へ残します。別環境で同じ結果が必要なら、データ仕様で照合規則を固定します。

LC_ALL=C sort -u -- input.txt > unique-byte-order-20260716.txt

ファイル内の重複状況を先に調べる

いきなり一意化せず、元行数、一意行数、重複値と件数を別ファイルへ出して影響を見積もります。機密データでは重複行そのものを画面へ出さず、件数だけを確認するか、承認された保護先へ保存します。入力が更新中なら各計測時点が異なるため、固定したコピーで比較します。

wc -l -- input.txt
sort -- input.txt | uniq -c > duplicate-audit-20260716.txt

元行数から出力行数を引いた値は削除される重複出現数の目安ですが、末尾改行の有無やエラーを確認します。出力が0バイト、途中で容量不足、文字コードエラーになっていないか、終了状態を必ず見ます。

原本を守る安全な手順

  1. 入力ファイルの絶対パス、所有者、権限、サイズ、更新時刻、ハッシュが必要かを記録する。
  2. 「同じ」の定義、並び順維持、空行、文字コード、ロケール、期待する出力行数を決める。
  3. 原本とは別ディレクトリまたは別名の新規ファイルへ出力し、同名が存在しないことを確認する。
  4. コマンドとパイプラインの終了状態、出力サイズ、行数、先頭・末尾、抜き取りサンプルを検証する。
  5. 原本と出力の差分をレビューし、メタデータとアクセス権をどう引き継ぐか決める。
  6. アプリ停止やファイルロックが必要か確認し、承認済みの原子的な置換手順と復旧手順を使う。
  7. 置換後に利用アプリの読み込み、監視、バックアップを確認し、旧版を保持期限に従って管理する。

一時ファイルを同じディレクトリへ作ってmvする方法は、同一ファイルシステムなら原子的に名前を切り替えられる場合がありますが、所有者、権限、ACL、拡張属性、SELinuxラベル、ハードリンク、監視ツール、開いているプロセスへ影響します。単純なコマンド例で本番原本を置換せず、アプリケーションと組織の正式手順を使います。

入力ファイルを出力先にしない

sort -u input.txt > input.txtやawk ... input.txt > input.txtは危険です。シェルが入力プログラムを起動する前に同じ出力ファイルを切り詰め、入力が空になります。ツールの出力先オプションが入力と同じ名前を安全に扱えるかも製品ごとに異なります。必ず新しい名前へ出力し、成功検証後に別工程として置換します。

巨大ファイルと容量

  • sortの一時領域と出力領域の両方を見積もり、ネットワーク共有や本番ルート領域を圧迫しない。
  • awkのseen配列は一意行数に比例してメモリを使うため、順序維持の代償を見積もる。
  • 長大な1行、NULを含むレコード、圧縮ファイル、異なる文字コードを通常の行処理へ直接渡さない。
  • 処理中に入力が追記されるなら、整合したスナップショットやアプリのエクスポート機能を使う。
  • CPU、I/O、メモリ、実行時間を監視し、同じ処理を焦って並列再実行しない。
  • 途中出力と検証済み出力を名前や台帳で区別し、未完成ファイルを後段が読まないようにする。

用途別の選択

  • 隣接した重複だけをまとめる:uniq。既に適切に整列またはグループ化されている入力向け。
  • 順序を変えて全体を一意化する:sort -u。外部ソートで大きなデータを扱いやすい。
  • 重複件数を集計する:sort | uniq -c。pipefailと出力形式に注意する。
  • 最初の出現順を保つ:awk !seen[$0]++。一意行数に応じたメモリを確認する。
  • CSVやJSONの特定列をキーにする:形式専用パーサーまたはデータベースを使う。
  • 巨大データで厳密な照合規則がある:ETL、SQL、分散処理など監査可能な基盤を検討する。

重複行削除で最初に選ぶのはコマンドではなく、順序と一致条件です。順序不要ならsort -u、順序維持ならawk、隣接重複だけならuniqが基本です。原本とは別の新規ファイルへ出力し、件数、差分、権限、終了状態を検証してから、承認された置換手順へ進めてください。

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次