バッチファイル(bat)でテキストファイルをソートしたい場面は多くあります。ログの日時順整列・設定ファイルの整理・CSVのキー列ソート・重複行の除去など、Windows 標準の sort コマンドだけで多くのケースに対応できます。本記事では基本の昇順・降順から、列位置指定・複数ファイル結合・重複除去・PowerShell による高機能ソートまで体系的に解説します。
この記事でできること
- sort コマンドで昇順・降順にテキストを並べ替える
- /+n オプションで列位置を指定してソートする
- 複数ファイルを結合して一括ソートする
- 重複行を除去しながらソートする
- PowerShell で大文字小文字無視・複数キー・安定ソートを行う
- 実践例3本(ログ整列・CSV上位抽出・マルチログ統合)と落とし穴・FAQ も解説
sort コマンドのオプション一覧
Windows 標準の sort コマンドで使える主要オプションをまとめます。
| オプション | 説明 | 例 |
|---|---|---|
| (なし) | 昇順ソート(デフォルト) | sort input.txt |
/R |
降順ソート | sort /R input.txt |
/+n |
n文字目から比較(1始まり) | sort /+5 input.txt |
/O ファイル |
出力先ファイルを指定(入力と同じファイルも可) | sort /O out.txt in.txt |
/L ロケール |
比較に使用するロケールを指定 | sort /L ja-JP input.txt |
/REC n |
レコード(行)の最大バイト数を指定 | sort /REC 4096 input.txt |
/T dir |
一時ファイルのディレクトリを指定 | sort /T C:\tmp input.txt |
Windows の sort コマンドはバイナリ比較(文字コード順)です。大文字・小文字の区別あり、日本語は文字コード順になります。数値の大小比較(例: 9より10を大きいと判断)は できません。数値・日本語・複数キーのソートには PowerShell を使ってください。
方法1: 基本の昇順・降順ソート
sort コマンドの最もシンプルな使い方です。/O オプションで出力先を指定すると、入力ファイルと同じファイルへの上書きも安全に行えます。
昇順ソート(A→Z・0→9)
@echo off setlocal set "INPUT=data.txt" set "OUTPUT=sorted_asc.txt" sort "%INPUT%" /O "%OUTPUT%" echo 昇順ソート完了: %OUTPUT% endlocal
降順ソート(Z→A・9→0)
@echo off setlocal set "INPUT=data.txt" set "OUTPUT=sorted_desc.txt" sort /R "%INPUT%" /O "%OUTPUT%" echo 降順ソート完了: %OUTPUT% endlocal
元ファイルに上書きソート
/O に入力ファイルと同じパスを指定すると、sort コマンドが内部で一時ファイルを使い安全に上書きしてくれます。
@echo off rem /O に入力と同じファイルを指定 → 安全に上書き sort /O data.txt data.txt echo 上書きソート完了
方法2: 列位置を指定してソート(/+n)
/+n オプションで比較開始位置(1始まりの文字位置)を指定できます。固定長フォーマットのログや、タブ区切りの列を文字位置で区切るデータに有効です。
5文字目から比較してソート
rem 例: 以下のような固定長ログ rem "2024-01-15 ERROR something happened" rem "2024-01-10 WARN minor issue" rem "2024-01-20 INFO started" rem → /+1 なら1文字目(日付)基準、/+12 ならレベル基準 @echo off setlocal set "INPUT=app.log" set "OUTPUT=sorted_by_level.log" rem 12文字目(ログレベル列)からソート sort /+12 "%INPUT%" /O "%OUTPUT%" echo レベル別ソート完了: %OUTPUT% endlocal
タイムスタンプが先頭にある固定長ログは
/+1 で日時順に並べられます。CSV のように列幅が可変の場合は PowerShell の Sort-Object を使う方が確実です。
方法3: 複数ファイルを結合して一括ソート
sort コマンド単体では複数ファイルを直接受け取れません。type コマンドでファイルを連結してパイプで渡すのが定番の方法です。
2ファイルを結合してソート
@echo off setlocal set "OUT=merged_sorted.txt" type log1.txt log2.txt | sort > "%OUT%" echo 結合・ソート完了: %OUT% endlocal
フォルダ内の全 .txt ファイルを結合してソート
@echo off setlocal set "OUT=all_sorted.txt" rem type で *.txt を全件連結してソート type *.txt | sort > "%OUT%" echo フォルダ内全TXTを結合・ソート完了: %OUT% endlocal
方法4: 重複行を除去してソート
sort コマンドだけでは重複行の除去はできません。PowerShell の Get-Content | Sort-Object -Unique を組み合わせます。
ソート+重複除去(PowerShell 連携)
@echo off
setlocal
set "INPUT=data.txt"
set "OUTPUT=unique_sorted.txt"
powershell -NoProfile -Command ^
"Get-Content '%INPUT%' | Sort-Object -Unique | Set-Content '%OUTPUT%' -Encoding UTF8"
echo 重複除去・ソート完了: %OUTPUT%
endlocal
sort → PowerShell で重複除去(大量データ向け)
@echo off
setlocal
set "INPUT=large.txt"
set "OUTPUT=unique_sorted.txt"
rem sort でまず並べ替えてから Get-Unique で隣接重複を除去(高速)
sort "%INPUT%" | powershell -NoProfile -Command ^
"$input | Get-Unique | Set-Content '%OUTPUT%' -Encoding UTF8"
echo 完了: %OUTPUT%
endlocal
方法5: PowerShell で多機能ソート
大文字・小文字の無視、数値順ソート、複数キー指定、安定ソートなど、sort コマンドでは対応できない高度なソートに PowerShell を使います。
大文字・小文字を区別しない昇順ソート
@echo off
setlocal
set "INPUT=data.txt"
set "OUTPUT=sorted_ci.txt"
powershell -NoProfile -Command ^
"Get-Content '%INPUT%' | Sort-Object {$_.ToLower()} | Set-Content '%OUTPUT%' -Encoding UTF8"
echo 大文字小文字無視ソート完了: %OUTPUT%
endlocal
数値順ソート(9より10を大きいと判断)
@echo off
setlocal
set "INPUT=numbers.txt"
set "OUTPUT=sorted_num.txt"
rem 各行を数値として解釈してソート
powershell -NoProfile -Command ^
"Get-Content '%INPUT%' | Sort-Object { [int]$_ } | Set-Content '%OUTPUT%' -Encoding UTF8"
echo 数値順ソート完了: %OUTPUT%
endlocal
CSV の特定列でソート
@echo off
setlocal
set "INPUT=data.csv"
set "OUTPUT=sorted_by_col.csv"
rem 2列目(Score)で数値降順ソートしてCSV出力
powershell -NoProfile -Command ^
"$rows = Import-Csv '%INPUT%' -Encoding UTF8;" ^
"$sorted = $rows | Sort-Object { [int]$_.Score } -Descending;" ^
"$sorted | Export-Csv '%OUTPUT%' -NoTypeInformation -Encoding UTF8"
echo CSV列ソート完了: %OUTPUT%
endlocal
複数キーでソート(第1キー: 部署, 第2キー: 名前)
@echo off
setlocal
set "INPUT=employees.csv"
set "OUTPUT=sorted_multi.csv"
powershell -NoProfile -Command ^
"$rows = Import-Csv '%INPUT%' -Encoding UTF8;" ^
"$sorted = $rows | Sort-Object Department, Name;" ^
"$sorted | Export-Csv '%OUTPUT%' -NoTypeInformation -Encoding UTF8"
echo 複数キーソート完了: %OUTPUT%
endlocal
実践例A: アプリログを日時順・レベル別に整列
想定データ: YYYY-MM-DD HH:MM:SS [LEVEL] メッセージ 形式のログファイル。日時順(昇順)に並べ替え、同一日時の場合はレベル別に整列します。
@echo off
setlocal enabledelayedexpansion
set "INPUT=app.log"
set "OUTPUT=app_sorted.log"
if not exist "%INPUT%" (
echo [ERROR] %INPUT% が見つかりません
exit /b 1
)
rem タイムスタンプが先頭にあるので /+1(1文字目から)で日時順ソート
sort /+1 "%INPUT%" /O "%OUTPUT%"
rem 件数確認
for /f %%C in ('find /c /v "" "%OUTPUT%"') do set "LINES=%%C"
echo ===========================
echo ログソート完了
echo 入力: %INPUT%
echo 出力: %OUTPUT% (%LINES% 行)
echo ===========================
endlocal
実践例B: CSVをスコア列で降順ソートして上位10件を抽出
想定データ: Name,Score,Date のCSV。スコア列で数値降順ソートし、ヘッダー付きで上位10件のみ抽出します。
@echo off
setlocal
set "INPUT=scores.csv"
set "OUTPUT=top10.csv"
set "TOP_N=10"
if not exist "%INPUT%" (
echo [ERROR] %INPUT% が見つかりません
exit /b 1
)
powershell -NoProfile -Command ^
"$rows = Import-Csv '%INPUT%' -Encoding UTF8;" ^
"$sorted = $rows | Sort-Object { [int]$_.Score } -Descending;" ^
"$top = $sorted | Select-Object -First %TOP_N%;" ^
"$top | Export-Csv '%OUTPUT%' -NoTypeInformation -Encoding UTF8;" ^
"Write-Host ('上位 %TOP_N% 件を抽出: ' + '%OUTPUT%')"
endlocal
実践例C: 複数サーバーのログを統合・重複除去・日時ソート
複数サーバーから収集したログファイル(server1.log, server2.log …)を結合し、重複行を除去して日時順に整列します。
@echo off
setlocal enabledelayedexpansion
set "LOG_DIR=logs"
set "MERGED=merged_temp.log"
set "OUTPUT=unified.log"
if not exist "%LOG_DIR%" (
echo [ERROR] ログフォルダが見つかりません: %LOG_DIR%
exit /b 1
)
rem ステップ1: 全ログを結合
type "%LOG_DIR%\*.log" > "%MERGED%"
rem ステップ2: 日時順ソート → 隣接重複除去
sort "%MERGED%" | powershell -NoProfile -Command ^
"$input | Get-Unique | Set-Content '%OUTPUT%' -Encoding UTF8"
rem 一時ファイルを削除
del /q "%MERGED%"
rem 件数レポート
for /f %%C in ('find /c /v "" "%OUTPUT%"') do set "LINES=%%C"
echo ===========================
echo ログ統合・整列完了
echo 出力: %OUTPUT% (%LINES% 行)
echo ===========================
endlocal
よくある落とし穴
落とし穴1: 数値が文字列として比較される(9 > 10)
sort は文字コード順比較のため、10 より 9 が後ろに来ます。数値の大小比較が必要な場合は PowerShell の Sort-Object { [int]$_ } を使ってください。
rem NG: sort コマンドは文字列比較
rem 入力: 10, 2, 9, 100, 20
rem 出力: 10, 100, 2, 20, 9 ← 文字列順
sort numbers.txt
rem OK: PowerShell で数値順
rem 出力: 2, 9, 10, 20, 100 ← 数値順
powershell -NoProfile -Command "Get-Content 'numbers.txt' | Sort-Object { [int]$_ }"
落とし穴2: 日本語が文字コード順になる
Windows の sort コマンドはバイナリ比較のため、日本語テキストは五十音順ではなく文字コード(CP932 または UTF-8)順に並びます。日本語の辞書順ソートは PowerShell の [System.StringComparer]::CurrentCulture を使います。
rem 日本語を辞書順ソート(PowerShell)
powershell -NoProfile -Command ^
"$comp = [System.StringComparer]::CurrentCulture;" ^
"Get-Content 'japanese.txt' | Sort-Object { $_ } -Culture ja-JP | Set-Content 'sorted_ja.txt'"
落とし穴3: BOM 付き UTF-8 ファイルで先頭に記号が付く
BOM 付き UTF-8 ファイルを sort でそのまま処理すると、先頭行の頭に BOM バイト(EF BB BF)が付き、ソート結果に影響します。PowerShell で BOM を除去してから処理してください。
rem BOM 除去してから sort
powershell -NoProfile -Command ^
"$text = [System.IO.File]::ReadAllText('bom.txt', [System.Text.Encoding]::UTF8);" ^
"if ($text.StartsWith([char]0xFEFF)) { $text = $text.Substring(1) };" ^
"[System.IO.File]::WriteAllText('nobom.txt', $text, [System.Text.Encoding]::UTF8)"
sort nobom.txt /O sorted.txt
落とし穴4: 空行が sort でスキップされない
sort は空行も1行として処理し、ソート結果に含めます。空行を除いてソートしたい場合は findstr /r /v "^$" でフィルタします。
rem 空行を除いてソート findstr /r /v "^$" data.txt | sort > sorted_no_blank.txt
落とし穴5: /+n の文字位置はバイト単位(マルチバイト注意)
sort /+n の n はバイト単位です。Shift-JIS では日本語1文字が2バイトのため、列位置計算がずれることがあります。日本語を含む固定長データの列指定ソートは PowerShell を使う方が安全です。
rem ASCII のみなら /+n が使えるが、日本語混在は PowerShell を推奨
powershell -NoProfile -Command ^
"Get-Content 'data.txt' | Sort-Object { $_.Substring(10) } | Set-Content 'sorted.txt'"
よくある質問(FAQ)
sort /O 元ファイル 元ファイル と同じファイルを指定すると安全に上書きできます。sort input.txt > input.txt のようにリダイレクトで上書きすると書き込みと読み込みが競合してファイルが空になるため注意してください。
rem OK: /O オプションで上書き sort /O data.txt data.txt rem NG: リダイレクトで上書きするとファイルが空になる sort data.txt > data.txt
タブ区切りファイルの列でソートするには PowerShell の Import-Csv -Delimiter "`t" を使います。
@echo off
rem タブ区切りファイルを2列目(Score)で降順ソート
powershell -NoProfile -Command ^
"$rows = Import-Csv 'data.tsv' -Delimiter "`t" -Encoding UTF8;" ^
"$rows | Sort-Object Score -Descending | Export-Csv 'sorted.tsv' -Delimiter "`t" -NoTypeInformation -Encoding UTF8"
sort コマンドは /T で一時ディレクトリを SSD 上に指定すると高速化できます。数百 MB 以上のファイルは PowerShell の StreamReader を使う方が効率的です。
rem sort の一時ディレクトリを SSD に指定して高速化
sort /T C:\SSD_Temp big_file.txt /O sorted_big.txt
rem PowerShell + Sort-Object で大容量ファイルを処理
powershell -NoProfile -Command ^
"Get-Content 'big_file.txt' -ReadCount 0 | Sort-Object | Set-Content 'sorted.txt'"
PowerShell の Sort-Object { $_.TrimStart() } を使うと、比較キーだけ先頭空白を除去してソートできます(出力は元の行が保たれます)。
powershell -NoProfile -Command ^
"Get-Content 'data.txt' | Sort-Object { $_.TrimStart() } | Set-Content 'sorted.txt' -Encoding UTF8"
PowerShell の Get-Random を使って行をランダムに並べ替えられます。テストデータ作成やサンプリングに便利です。
@echo off
rem テキストファイルをランダムにシャッフル
powershell -NoProfile -Command ^
"Get-Content 'data.txt' | Get-Random -Count ([int]::MaxValue) | Set-Content 'shuffled.txt' -Encoding UTF8"
まとめ
| 目的 | 推奨方法 | ポイント |
|---|---|---|
| シンプルな昇順ソート | sort input.txt /O output.txt | 追加ツール不要・高速 |
| 降順ソート | sort /R input.txt | /R オプション一つ追加 |
| 列位置指定ソート | sort /+n input.txt | 固定長フォーマットに有効 |
| 複数ファイル結合ソート | type *.txt | sort | パイプで渡すだけ |
| 重複除去 | sort | Get-Unique | sort でソート後に隣接重複を除去 |
| 数値順ソート | PowerShell Sort-Object { [int]$_ } | 文字列比較の罠を回避 |
| CSV 列ソート | PowerShell Import-Csv | Sort-Object | 列名指定で安全 |
| 大文字小文字無視 | Sort-Object { $_.ToLower() } | sort コマンドは区別あり |
ASCII テキストの単純な昇順・降順なら sort コマンドで十分です。数値・日本語・複数キー・CSV 列ソートが必要になったら PowerShell に切り替えましょう。
テキストファイルの処理をさらに発展させるなら、特定の文字列を含むファイルを別フォルダにコピーする方法 や、CSVファイルを分割する方法 も合わせて参照してください。
