【bat】テキストファイルをソートし重複行を削除する方法完全ガイド|sort・PowerShell・for /f・CSV列指定・大文字小文字無視まで徹底解説

ログファイルの整理・IP アドレスリストの名寄せ・設定ファイルの重複エントリ除去……。テキストファイルをソートして重複行を削除したい場面は実務で頻繁に発生します。Windows の sort コマンドは重複削除オプションを持たないため、PowerShell や for /f を組み合わせる必要があります。この記事では目的別に最適な方法を体系的に解説します。

Windows の sort コマンドに /uniq オプションはない
Linux/macOS では sort -uuniq コマンドで重複削除できますが、Windows の sort コマンドには重複削除オプションがありません。ネット上には sort | uniq と書かれた記事もありますが、uniq は Windows に標準搭載されていないため動作しません。正しくは PowerShell または for /f を使います。
この記事でわかること

  • Windows sort コマンドの基本(/R 降順・/+n 列指定)
  • PowerShell Sort-Object -Unique でソート&重複削除(推奨)
  • バッチ単独で重複削除する方法(for /f 前行比較)
  • 大文字小文字を無視した重複削除
  • CSV の特定列で重複チェックする方法
  • 空行・コメント行を除去しながらソートする方法
  • 実践例3本(ログ整理・IPリスト名寄せ・設定ファイル重複除去)
スポンサーリンク

1. Windows sort コマンドの基本

まず前提として Windows の sort コマンドでできることを整理します。

オプション 意味
(なし) 昇順ソート(A→Z、0→9) sort input.txt
/R 降順ソート(Z→A、9→0) sort /R input.txt
/+n 先頭から n 文字目を基準にソート sort /+5 input.txt
/O ファイル 結果を指定ファイルに出力(自ファイル可) sort input.txt /O input.txt
/L ロケール ソートのロケールを指定 sort /L ja input.txt
@echo off

:: 昇順ソートして別ファイルに出力
sort input.txt > sorted.txt

:: 降順ソート
sort /R input.txt > sorted_desc.txt

:: 上書き保存(/O で入力と同じファイルに出力可能)
sort input.txt /O input.txt

:: 5文字目を基準にソート(日付フィールドなどに便利)
sort /+5 input.txt > sorted.txt
sort /O で入力ファイルと出力ファイルを同じにできる
sort input.txt > input.txt はリダイレクト先を先に開くためファイルが空になりますが、sort input.txt /O input.txt は安全に上書きできます。ファイルをその場でソートしたいときに使ってください。

sort コマンドの詳細な使い方(降順・列位置・文字コード対応)は テキストファイルをソートする方法完全ガイド も参照してください。

2. PowerShell でソート&重複削除(推奨)

重複削除には PowerShell の Sort-Object -Unique が最も簡単・確実です。1行で「ソート+重複削除+ファイル保存」を実現できます。

2-1. 基本:ソート&重複削除

@echo off

:: ソートして重複行を削除(Shift_JIS ファイル)
powershell -Command ^^
    "Get-Content 'input.txt' | Sort-Object -Unique | Set-Content 'output.txt'"

:: UTF-8 ファイルの場合
powershell -Command ^^
    "Get-Content 'input.txt' -Encoding UTF8 | Sort-Object -Unique | Set-Content 'output.txt' -Encoding UTF8"

echo 完了: output.txt

2-2. 大文字小文字を無視して重複削除

@echo off

:: -CaseSensitive をつけない場合、大文字小文字は区別しない(デフォルト)
powershell -Command ^^
    "Get-Content 'input.txt' | Sort-Object -Unique | Set-Content 'output.txt'"

:: 大文字小文字を区別する場合は -CaseSensitive を追加
powershell -Command ^^
    "Get-Content 'input.txt' | Sort-Object -Unique -CaseSensitive | Set-Content 'output.txt'"
Sort-Object -Unique のデフォルトは大文字小文字を区別しない
Windows の Sort-Object -Unique は既定で大文字小文字を無視して重複判定します。ERRORerror は同じ行として扱われます。区別したい場合のみ -CaseSensitive を追加してください。

2-3. 降順ソートして重複削除

@echo off

:: 降順ソート + 重複削除
powershell -Command ^^
    "Get-Content 'input.txt' | Sort-Object -Unique -Descending | Set-Content 'output.txt'"

2-4. 空行も除去しながら重複削除

@echo off

:: 空行・コメント行(#始まり)を除去してからソート・重複削除
powershell -Command ^^
    "Get-Content 'input.txt' | Where-Object { $_ -ne '' -and $_ -notmatch '^#' } | Sort-Object -Unique | Set-Content 'output.txt'"

:: さらに前後の空白もトリムする
powershell -Command ^^
    "Get-Content 'input.txt' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } | Sort-Object -Unique | Set-Content 'output.txt'"

3. バッチ単独で重複削除する方法(for /f 前行比較)

PowerShell が使えない環境や、純粋なバッチスクリプトで完結させたい場合はfor /f で前の行と比較しながら重複を除外する方法を使います。ただしソート済みのファイルが前提です(ソートすれば重複が隣接するため)。

@echo off
setlocal enabledelayedexpansion

:: ステップ1: まず sort でソート
sort input.txt > sorted_tmp.txt

:: ステップ2: 前の行と比較しながら重複を除外
set PREV_LINE=
if exist output.txt del output.txt

for /f "usebackq delims=" %%L in ("sorted_tmp.txt") do (
    :: 前の行と同じなら出力しない
    if not "%%L"=="!PREV_LINE!" (
        echo %%L >> output.txt
    )
    set PREV_LINE=%%L
)

del sorted_tmp.txt
echo 重複削除完了: output.txt
この方法は空行・特殊文字を含む行で誤動作する可能性がある
for /f は空行をスキップするため、空行が重複チェックの対象外になります。また、!% を含む行は遅延展開の影響で正しく比較できないことがあります。信頼性が必要な場合は PowerShell の Sort-Object -Unique を使ってください。

3-1. 重複行を数えてレポートする(除去せず集計)

@echo off
setlocal enabledelayedexpansion

:: ソート後に重複行を検出してカウント
sort input.txt > sorted_tmp.txt

set PREV_LINE=
set DUP_COUNT=0
set UNIQ_COUNT=0

for /f "usebackq delims=" %%L in ("sorted_tmp.txt") do (
    if "%%L"=="!PREV_LINE!" (
        set /a DUP_COUNT+=1
    ) else (
        set /a UNIQ_COUNT+=1
    )
    set PREV_LINE=%%L
)

del sorted_tmp.txt
echo ユニーク行数: %UNIQ_COUNT%
echo 重複行数   : %DUP_COUNT%

4. CSV の特定列で重複チェック・削除する

「メールアドレス列が重複する行を除去する」のように、特定の列(フィールド)を基準に重複を判定したい場合は PowerShell が最も適しています。

4-1. 特定列(n列目)を基準に重複削除

@echo off

:: CSV の 2列目(インデックス1)を基準に重複削除(ヘッダー行を保持)
powershell -Command ^^
    "$data = Import-Csv 'input.csv' -Encoding Default;" ^^
    "$unique = $data | Sort-Object -Property 'メールアドレス' -Unique;" ^^
    "$unique | Export-Csv 'output.csv' -NoTypeInformation -Encoding Default"

echo CSV 重複削除完了: output.csv

4-2. PowerShell で複数列の組み合わせを基準に重複削除

@echo off

:: 姓+名の組み合わせが重複する行を削除(姓列・名前列の両方が一致したら重複)
powershell -Command ^^
    "$data = Import-Csv 'input.csv' -Encoding Default;" ^^
    "$unique = $data | Sort-Object -Property @('姓','名前') -Unique;" ^^
    "$unique | Export-Csv 'output.csv' -NoTypeInformation -Encoding Default"

:: ヘッダーなしの CSV(タブ区切り)で1列目を基準に重複削除
powershell -Command ^^
    "Import-Csv 'input.tsv' -Delimiter "`t" -Header @('id','name','dept') |" ^^
    "Sort-Object -Property id -Unique |" ^^
    "Export-Csv 'output.tsv' -Delimiter "`t" -NoTypeInformation"
CSV の列指定重複削除は PowerShell が圧倒的に簡単・確実
バッチ単独で CSV の特定列による重複チェックを実装すると非常に複雑になります。CSV を扱う場合は Import-Csv / Export-Csv を使う PowerShell が圧倒的に簡単・信頼性が高いです。バッチから PowerShell を呼び出す形で実装することを強く推奨します。

CSV ファイルの読み込み・列指定処理については CSV ファイルを読み込む方法完全ガイド も参照してください。

5. 応用:条件付き重複削除パターン

5-1. 数値として並べ替えてから重複削除

@echo off

:: 数値としてソート(文字列ソートと結果が異なる)
:: 例: 1, 2, 10, 20 → 文字列ソートでは 1, 10, 2, 20 になる
powershell -Command ^^
    "Get-Content 'numbers.txt' | ForEach-Object { [int]$_ } | Sort-Object -Unique | Set-Content 'output.txt'"

:: IPアドレスを数値的にソート
powershell -Command ^^
    "Get-Content 'ips.txt' | Sort-Object { [version]$_ } -Unique | Set-Content 'output.txt'"

5-2. 特定のパターンを含む行だけ重複削除する

@echo off

:: ERRORを含む行のみ抽出してソート・重複削除
powershell -Command ^^
    "Get-Content 'app.log' | Where-Object { $_ -match 'ERROR' } | Sort-Object -Unique | Set-Content 'errors_unique.txt'"

:: 重複削除後の行数を確認
for /f %%N in ('type errors_unique.txt ^| find /c /v ""') do echo ユニークなエラー: %%N 種類

5-3. 元の順番を保ったまま重複だけ削除する(初出を保持)

@echo off

:: ソートせず、最初に出てきた行だけを残す(出現順を保持)
powershell -Command ^^
    "$seen = @{};" ^^
    "Get-Content 'input.txt' | Where-Object {" ^^
        "$key = $_.ToLower();" ^^
        "if (-not $seen[$key]) { $seen[$key] = $true; $true } else { $false }" ^^
    "} | Set-Content 'output.txt'"

echo 初出保持・重複削除完了: output.txt
Sort-Object -Unique はソート順になる(出現順ではない)
Sort-Object -Unique は結果がアルファベット順になります。元ファイルの行の出現順を保ったまま重複だけ削除したい場合は、ハッシュテーブルを使った「初出保持」の方法(上記)を使ってください。

6. 実践例3本

実践例1:ログファイルのエラーメッセージを整理する

@echo off
setlocal

:: 複数ログファイルから ERROR 行を抽出・ソート・重複削除して一覧化
set LOGDIR=C:applogs
set OUTPUT=C:workunique_errors.txt

if exist "%OUTPUT%" del "%OUTPUT%"

:: 全ログファイルを結合して一時ファイルに
for %%F in ("%LOGDIR%*.log") do (
    type "%%F" >> all_logs_tmp.txt
)

:: ERROR 行を抽出・ソート・重複削除
powershell -Command ^^
    "Get-Content 'all_logs_tmp.txt' |" ^^
    "Where-Object { $_ -match 'ERROR' } |" ^^
    "ForEach-Object { ($_ -replace '^.*?ERROR', 'ERROR').Trim() } |" ^^
    "Sort-Object -Unique |" ^^
    "Set-Content '%OUTPUT%'"

del all_logs_tmp.txt

:: 結果の件数表示
for /f %%N in ('type "%OUTPUT%" ^| find /c /v ""') do echo ユニークなエラー: %%N 種類
echo 出力先: %OUTPUT%

実践例2:IPアドレスリストの名寄せ(重複除去・数値順ソート)

@echo off

:: 複数ソースから集めた IP アドレスリストを整理
:: input.txt 例:
:: 192.168.1.10
:: 10.0.0.5
:: 192.168.1.10  ← 重複
:: 172.16.0.1

:: 空行・コメントを除去 → IP アドレスとして数値ソート → 重複削除
powershell -Command ^^
    "Get-Content 'input.txt' |" ^^
    "ForEach-Object { $_.Trim() } |" ^^
    "Where-Object { $_ -match '^d{1,3}.d{1,3}.d{1,3}.d{1,3}$' } |" ^^
    "Sort-Object { [version]$_ } -Unique |" ^^
    "Set-Content 'output_ips.txt'"

for /f %%N in ('type output_ips.txt ^| find /c /v ""') do echo ユニーク IP: %%N 件
echo 出力先: output_ips.txt

実践例3:設定ファイルの重複キーを除去する(最後の値を優先)

@echo off

:: 設定ファイル(KEY=VALUE 形式)の重複キーを除去
:: 同じキーが複数ある場合は最後の値を優先する
:: 例:
::   HOST=server01
::   PORT=8080
::   HOST=server02  ← この HOST が優先される

powershell -Command ^^
    "$result = @{};" ^^
    "Get-Content 'config.txt' | ForEach-Object {" ^^
        "if ($_ -match '^([^=]+)=(.*)$') {" ^^
            "$result[$Matches[1].Trim()] = $Matches[2].Trim()" ^^
        "}" ^^
    "};" ^^
    "$result.GetEnumerator() | Sort-Object Key | ForEach-Object { '$($_.Key)=$($_.Value)' } | Set-Content 'config_clean.txt'"

echo 重複キー除去完了: config_clean.txt
type config_clean.txt

テキストファイルの表示・結合・パイプ処理については typeコマンド完全ガイド、ファイルへの書き込みは リダイレクト完全ガイド も参照してください。

7. まとめ:目的別チートシート

やりたいこと 方法 コマンド例
ソートのみ(重複除去なし) sort コマンド sort input.txt /O input.txt
ソート+重複削除(推奨) PowerShell Sort-Object -Unique powershell "Get-Content f.txt | Sort-Object -Unique | Set-Content o.txt"
大文字小文字を区別して重複削除 PowerShell -CaseSensitive Sort-Object -Unique -CaseSensitive
降順ソート+重複削除 PowerShell -Descending Sort-Object -Unique -Descending
出現順を保ったまま重複削除 PowerShell ハッシュテーブル $seen=@{}; Where-Object { $seen[$_] -eq $null -and ($seen[$_]=1) }
空行・コメントも除去 PowerShell Where-Object Where-Object { $_ -ne '' -and $_ -notmatch '^#' }
IP アドレスを数値順ソート PowerShell [version]キャスト Sort-Object { [version]$_ } -Unique
CSV の特定列で重複削除 PowerShell Import-Csv Import-Csv f.csv | Sort-Object -Property 列名 -Unique | Export-Csv o.csv
バッチ単独で重複削除 sort + for /f 前行比較 sort → for /f で !PREV_LINE! と比較

FAQ

Qsort | uniq と書いてある記事がありましたが Windows で使えますか?

A使えません。uniq は Linux/macOS の標準コマンドであり、Windows には標準インストールされていません。sort | uniq を実行すると「’uniq’ は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」というエラーになります。Windows では PowerShell の Sort-Object -Unique を使ってください。

Qsort /u や sort -u は Windows で使えますか?

A使えません。Windows の sort コマンドには /u(unique)オプションはありません。使えるオプションは /R(降順)・/+n(列指定)・/O(出力ファイル指定)・/L(ロケール指定)のみです。

Q重複削除後もソートしたくない(元の順番を保ちたい)のですが。

ASort-Object -Unique はソートと重複削除を同時に行うため、順番が変わります。元の出現順を保ったまま重複だけ削除するには、ハッシュテーブルを使った「初出保持」の方法を使ってください:$seen=@{}; Get-Content f.txt | Where-Object { $k=$_.ToLower(); if(-not $seen[$k]){$seen[$k]=$true;$true}else{$false} } | Set-Content o.txt

QUTF-8 ファイルを処理したら文字化けしました。

APowerShell の Get-Content はデフォルトで Shift_JIS(Windows の規定エンコード)で読み込みます。UTF-8 ファイルには -Encoding UTF8 を、Set-Content 側にも -Encoding UTF8 を指定してください。BOM なし UTF-8 で書き出すには [System.IO.File]::WriteAllText(path, content, UTF8NoBOM) を使います。

Q重複している行だけを抽出したい(除去ではなく確認したい)。

APowerShell でグループ化してカウントする方法が簡単です:Get-Content f.txt | Group-Object | Where-Object { $_.Count -gt 1 } | Select-Object Name, Count | Sort-Object Count -Descending。これで「どの行が何回重複しているか」が一覧で確認できます。

Q100万行を超える大きなファイルでも動作しますか?

APowerShell の Get-Content は全行をメモリに読み込むため、非常に大きなファイルではメモリ不足になることがあります。大容量ファイルには sort コマンド(外部ファイルへの書き込みで省メモリ)とfor /f 前行比較の組み合わせ、または Get-Content -ReadCount 1000 でチャンク読み込みする方法を検討してください。