ログファイルの整理・IP アドレスリストの名寄せ・設定ファイルの重複エントリ除去……。テキストファイルをソートして重複行を削除したい場面は実務で頻繁に発生します。Windows の sort コマンドは重複削除オプションを持たないため、PowerShell や for /f を組み合わせる必要があります。この記事では目的別に最適な方法を体系的に解説します。
Linux/macOS では
sort -u や uniq コマンドで重複削除できますが、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 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'"
Windows の
Sort-Object -Unique は既定で大文字小文字を無視して重複判定します。ERROR と error は同じ行として扱われます。区別したい場合のみ -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 の特定列による重複チェックを実装すると非常に複雑になります。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 は結果がアルファベット順になります。元ファイルの行の出現順を保ったまま重複だけ削除したい場合は、ハッシュテーブルを使った「初出保持」の方法(上記)を使ってください。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 でチャンク読み込みする方法を検討してください。