バッチファイルで日本語を扱うと、文字化けが発生することがあります。原因は単純なようで意外に多層的で、「バッチファイルの保存エンコーディング」「コマンドプロンプトのコードページ(文字コード設定)」「コマンドの挙動の違い」が複雑に絡み合っています。本記事では文字化けが起きる仕組みを根本から解説し、場面ごとの確実な解決策を示します。
- コードページ(CP932/CP65001)と保存エンコーディングの関係
- 文字化けパターン別の原因と見分け方
- Shift-JIS(CP932)環境での正しいバッチの書き方
- UTF-8(chcp 65001)環境での注意点と落とし穴
for /fで日本語ファイルを読むときの文字化け対策- ログファイル・リダイレクト出力の文字化け対策
- PowerShell を介した確実なUTF-8処理
1. 文字化けの仕組み:コードページとエンコーディング
Windowsのコマンドプロンプト(cmd.exe)は、コードページ(Code Page)という文字コードの設定を持っています。日本語版Windowsのデフォルトは CP932(Shift-JIS の Microsoft 拡張版)です。バッチファイルの文字化けは、「バッチファイルの保存エンコーディング」と「コマンドプロンプトのコードページ」が一致しないことで発生します。
| コードページ | 番号 | 文字コード | 用途 |
|---|---|---|---|
CP932 |
932 |
Shift-JIS (MS拡張) | Windows日本語版デフォルト。バッチは通常これで動く |
CP65001 |
65001 |
UTF-8 | Unicode対応。chcp 65001 で切り替え |
CP20932 |
20932 |
EUC-JP | Linuxファイルの移植時などで稀に登場 |
:: 現在のコードページを確認する chcp :: 出力例(日本語Windows デフォルト) :: 現在のコード ページ: 932 :: UTF-8に切り替える chcp 65001 :: Shift-JISに戻す chcp 932
chcp の詳細な使い方・切り替え方法については 文字化けを直す方法|chcp 65001・UTF-8・Shift-JIS の使い分け も参照してください。
2. 文字化けパターン別の原因と見分け方
文字化けの見た目によって原因が異なります。よくあるパターンを整理します。
| 症状 | 主な原因 | 対処法の目安 |
|---|---|---|
バッチを実行すると echo の日本語が ? や 縺 の羅列になる |
バッチはUTF-8保存だがコードページがCP932(または逆) | バッチをShift-JIS保存に変えるか、冒頭に chcp 65001 を追加 |
chcp 65001 を入れたのに化ける |
バッチファイルがShift-JIS保存のまま | バッチファイルをUTF-8(BOM付き推奨)で保存し直す |
| 画面表示は正常だがログファイルに書いたら化ける | リダイレクト(>)はコードページに従うが受け側エンコードが違う |
chcp を合わせるかPowerShellで書き込む |
for /f でテキストファイルを読むと化ける |
for /f はCP932固定で処理することがある |
UTF-8ファイルはBOM付きにするかPowerShellで変換 |
| 変数に格納した日本語が空になる、または途切れる | BOMが変数先頭に混入、またはfor /fのdelims設定ミス | BOM除去・delims= 指定確認 |
| Shift-JISで正常だったバッチをUTF-8環境に持ち込むと化ける | ファイルは変わっていないがコードページが変わっている | chcp 932 で戻す、またはファイルをUTF-8で保存し直す |
3. 解決策1:バッチをShift-JIS(CP932)で保存する(最も互換性が高い)
日本語Windowsのデフォルトコードページは CP932(Shift-JIS) です。バッチファイルをShift-JISで保存すれば、chcp の変更なしに日本語が動作します。社内ツールや古い環境との共存が必要な場合に最も安全な選択肢です。
| エディタ | Shift-JIS保存の手順 |
|---|---|
| メモ帳(Windows 10以前) | ファイル→名前を付けて保存→文字コード:ANSI(= CP932) |
| メモ帳(Windows 11) | ファイル→名前を付けて保存→文字コード:Shift JIS |
| VSCode | 右下の文字コード表示をクリック →「エンコード付きで保存」→「Shift JIS」 |
| Notepad++ | エンコード → 「Shift-JIS に変換」→ 保存 |
| サクラエディタ | ファイル → 名前を付けて保存 → 文字コードセット:Shift JIS |
@echo off :: このファイルをShift-JIS(ANSI)で保存すること :: chcp 変更は不要 - CP932のまま日本語が動作する echo バッチファイルのテスト echo 日本語が正常に表示されます set NAME=テスト echo 変数: %NAME% pause
Shift-JISはWindowsネイティブで動作しますが、絵文字・一部漢字(?など補助漢字)は扱えません。また、GitやVSCodeはデフォルトでUTF-8として扱うため、チームでバージョン管理する場合は注意が必要です。
4. 解決策2:chcp 65001でUTF-8環境に切り替える
chcp 65001 を使うとコードページをUTF-8に切り替えられます。ただし、バッチファイル自体もUTF-8で保存する必要があります。またいくつかの落とし穴があるため、正しく使うポイントを押さえてください。
4-1. UTF-8バッチの基本構成
@echo off chcp 65001 >nul 2>&1 :: ^^^^^^^^ chcp の出力メッセージを非表示にする :: このファイルをUTF-8(BOM付き)で保存すること echo こんにちは echo UTF-8で日本語が表示されます pause
4-2. chcp 65001 の落とし穴
- echo が正常に動かない場合がある: Windows の古いバージョンや特定の環境では
chcp 65001にしてもechoが文字化けすることがあります。 - set /p の入力が壊れることがある: ユーザー入力を受け取る
set /pで 入力値が正しく格納されないケースがあります。 - for /f がShift-JISファイルを正しく読めない: コードページをUTF-8に変えても
for /fはバイト列をそのまま処理するため、Shift-JISファイルの内容が化けることがあります。 - 一部のコマンド出力が化ける:
dirやnetなどの出力が CP932固定のため化ける場合があります。
@echo off chcp 65001 >nul 2>&1 :: 問題が出る場合のWorkaround: PowerShell経由でechoする powershell -Command "Write-Host 'UTF-8で確実に表示したいテキスト'" :: または -NoProfile で起動時間を短縮 powershell -NoProfile -Command "Write-Host 'テキスト'"
PowerShellとの連携については PowerShellをバッチファイルから呼び出す方法 も参照してください。
5. UTF-8 BOM付き保存 vs BOMなし保存の違い
UTF-8には BOM付き(UTF-8 with BOM) と BOMなし(UTF-8 without BOM) の2種類があります。バッチファイルでは BOM付きが推奨です。
| 種類 | バッチでの動作 | エディタでの設定名 |
|---|---|---|
| Shift-JIS | デフォルトCP932で正常動作。chcp変更不要 |
ANSI / Shift-JIS |
| UTF-8 BOM付き | chcp 65001 と組み合わせで動作。BOM(EF BB BF)が先頭に付くが、cmdはこれを自動処理してくれる |
UTF-8 BOM付き / UTF-8 with BOM |
| UTF-8 BOMなし | BOMがないためcmdがShift-JISと誤認しやすい。chcp 65001を設定しても 化ける場合がある |
UTF-8 / UTF-8 without BOM |
VSCodeで新規作成したファイルはデフォルトで UTF-8 BOMなしです。バッチファイルとして保存する場合は右下の文字コードをクリックして 「エンコード付きで保存」→「UTF-8 with BOM」を選択してください。または
files.encoding 設定で utf8bom を指定することもできます。6. for /f でテキストファイルを読み込む際の文字化け対策
for /f はテキストファイルを1行ずつ読み込む強力なコマンドですが、文字コードの扱いに癖があります。コードページをUTF-8に変えても、for /f の内部処理はCP932前提のまま動くことがあり、UTF-8ファイルを読むと化けるケースがあります。
6-1. 問題:UTF-8ファイルをfor /fで読むと化ける
@echo off
chcp 65001 >nul 2>&1
:: UTF-8 BOMなしファイルを読むと化けることがある
for /f "usebackq delims=" %%L in ("C:\work\data_utf8.txt") do (
echo %%L
)
:: UTF-8 BOM付きファイルはfor /fで先頭にBOM文字が混入することがある
:: → 変数先頭の3バイト(EF BB BF)が余計に付く
6-2. 解決策A:ファイルをShift-JISで保存する
@echo off
:: for /f で読むテキストファイルをShift-JISで保存しておく
:: → CP932環境で確実に動く
for /f "usebackq delims=" %%L in ("C:\work\data_sjis.txt") do (
echo %%L
)
6-3. 解決策B:PowerShell経由でUTF-8ファイルを読む
@echo off
chcp 65001 >nul 2>&1
:: PowerShellでUTF-8ファイルを読み、各行を処理する
for /f "usebackq delims=" %%L in (`powershell -NoProfile -Command "Get-Content -Path 'C:\work\data_utf8.txt' -Encoding UTF8"`) do (
echo %%L
)
6-4. 解決策C:PowerShellでShift-JISに変換してから処理する
@echo off
:: UTF-8ファイルをShift-JISに変換してから for /f で処理する
set TMP_FILE=%TEMP%\conv_sjis.txt
powershell -NoProfile -Command "Get-Content -Path 'C:\work\data_utf8.txt' -Encoding UTF8 | Set-Content -Path '%TMP_FILE%' -Encoding Default"
for /f "usebackq delims=" %%L in ("%TMP_FILE%") do (
echo %%L
)
del "%TMP_FILE%"
for /f を使ったファイル読み込みの詳細・BOM処理については バッチでUnicodeファイルを扱えない原因と解決策完全ガイド も参照してください。
7. ログファイル・リダイレクト出力の文字化け対策
バッチの出力を > や >> でファイルに書き出すと、コードページに従ったエンコーディングでファイルが作られます。CP932のままリダイレクトするとShift-JISのファイルができ、UTF-8を期待するツールで開くと化けます。
7-1. Shift-JISでログを出力する(最も確実)
@echo off :: デフォルト(CP932)のままリダイレクトするとShift-JISのログになる echo [%date% %time%] 処理開始 >> "C:\logs\app.log" echo [%date% %time%] 処理完了 >> "C:\logs\app.log" :: ログをShift-JISで読む場合は通常のテキストエディタで開けばOK
7-2. UTF-8でログを出力する(PowerShell使用)
@echo off
chcp 65001 >nul 2>&1
:: PowerShell Out-File でUTF-8(BOMなし)のログを書く
set LOG=C:\logs\app_utf8.log
powershell -NoProfile -Command "[System.IO.File]::AppendAllText('%LOG%', '[処理開始]' + [Environment]::NewLine, [System.Text.Encoding]::UTF8)"
:: または Tee-Object でリアルタイム表示しながらUTF-8で書き出す
powershell -NoProfile -Command "Invoke-Command { Write-Output '処理中...' } | Tee-Object -FilePath '%LOG%' -Append"
7-3. typeコマンドで文字化けを確認する
:: ファイルの内容とコードページが合っているか確認 chcp type "C:\logs\app.log" :: 化ける場合はchcpを変えて試す chcp 65001 type "C:\logs\app.log" chcp 932 type "C:\logs\app.log"
type コマンドの文字コード処理については typeコマンド完全ガイド も参照してください。
8. 日本語ファイル名の文字化け
ファイル名に日本語が含まれる場合も文字化けが発生します。特に for ループでファイルを列挙するときに問題になります。
@echo off
:: 日本語ファイル名をfor でループする基本
:: CP932環境なら通常問題ない
for %%F in (C:\work\*) do (
echo %%~nxF
)
:: UTF-8環境(chcp 65001)でも日本語ファイル名を扱う場合は
:: dir /b 経由で取得するとより安全
for /f "usebackq delims=" %%F in (`dir /b "C:\work\*"`) do (
echo %%F
)
日本語ファイル名の詳細な扱い方については 日本語ファイル名を扱うときの注意点と解決策 も参照してください。
9. 実践例3本
実践例1:Shift-JIS環境で安定動作する日本語ログバッチ
チームのPC環境がバラバラでも動くように、Shift-JIS保存+CP932を前提とした最も互換性の高い構成です。
@echo off
:: ファイルはShift-JISで保存すること(デフォルト設定のまま動く)
setlocal enabledelayedexpansion
set LOG=%~dpn0.log
:: 実行日時を取得
for /f "tokens=1-3 delims=/ " %%A in ("%date%") do set DATE_STR=%%A%%B%%C
for /f "tokens=1-2 delims=: " %%A in ("%time: =0%") do set TIME_STR=%%A%%B
call :log "処理開始"
:: 処理本体
echo 日本語のメッセージを処理します
call :log "処理完了"
echo ログ: %LOG%
pause
exit /b 0
:log
echo [%DATE_STR%_%TIME_STR%] %~1 >> "%LOG%"
echo [%DATE_STR%_%TIME_STR%] %~1
exit /b 0
実践例2:UTF-8 CSV(BOM付き)をfor /fで正しく読み込む
UTF-8 BOM付きのCSVファイルを読む場合、先頭行のBOMを除去する処理が必要です。以下は最初の行(ヘッダー)をスキップしながら本文を処理する例です。
@echo off
:: CSVファイルはShift-JIS保存を推奨
:: どうしてもUTF-8 BOM付きを読む場合は以下のPowerShell方式を使う
set CSV=C:\work\data.csv
set TMP=%TEMP%\data_sjis.csv
:: UTF-8 CSVをShift-JISに変換(for /f で安全に読めるようにする)
powershell -NoProfile -Command "Get-Content -Path '%CSV%' -Encoding UTF8 | Select-Object -Skip 1 | Set-Content -Path '%TMP%' -Encoding Default"
:: 変換後のShift-JISファイルをfor /fで処理
for /f "usebackq tokens=1,2,3 delims=," %%A in ("%TMP%") do (
echo 列1=%%A 列2=%%B 列3=%%C
)
del "%TMP%"
CSVファイルの読み込み処理の詳細は バッチファイルでCSVファイルを読み込む方法完全ガイド も参照してください。
実践例3:コードページを自動判定して文字化けを回避するユーティリティ
実行環境のコードページに応じてUTF-8/Shift-JISを切り替えつつ、どちらの環境でも日本語を正しく出力します。
@echo off
setlocal enabledelayedexpansion
:: 現在のコードページを取得
:: 日本語環境: "現在のコード ページ: 932"
:: 英語環境: "Active code page: 932"
:: いずれも ":" の後の数字を取得する
for /f "tokens=2 delims=:" %%C in ('chcp') do set CUR_CP=%%C
set CUR_CP=!CUR_CP: =!
echo 現在のコードページ: !CUR_CP!
if "!CUR_CP!"=="932" (
echo [CP932環境] Shift-JIS モードで動作します
call :msg_sjis
) else if "!CUR_CP!"=="65001" (
echo [CP65001環境] UTF-8 モードで動作します
call :msg_utf8
) else (
echo [不明なCP !CUR_CP!] PowerShell でメッセージ表示します
powershell -NoProfile -Command "Write-Host 'コードページ: ' + [System.Console]::OutputEncoding.CodePage -ForegroundColor Yellow"
)
pause
exit /b 0
:msg_sjis
echo こんにちは(Shift-JISで表示)
exit /b 0
:msg_utf8
echo こんにちは(UTF-8で表示)
exit /b 0
10. まとめ:文字化け対策チートシート
| 状況 | 推奨する対処法 |
|---|---|
| 新規バッチを作る(最も安全・互換性重視) | バッチをShift-JIS(ANSI)で保存。chcp 変更不要 |
| UTF-8のバッチを書く | 冒頭に chcp 65001 >nul、ファイルはUTF-8 BOM付きで保存 |
for /f で日本語テキストを読む |
対象ファイルをShift-JIS保存、またはPowerShellで変換してから処理 |
| ログをUTF-8で書き出す | PowerShell [System.IO.File]::AppendAllText(..., UTF8) を使う |
| 日本語ファイル名をループ処理する | CP932環境なら通常問題なし。UTF-8環境では dir /b + for /f |
| 既存バッチが突然化けた | chcp で現在のコードページを確認し、バッチの保存エンコードと照合する |
| VSCodeでバッチを編集する | 右下の文字コードをクリック →「Shift JIS」または「UTF-8 with BOM」で保存 |
FAQ
Qchcp 65001 を入れたのにまだ文字化けします。
Achcp 65001 を追加するだけでなく、バッチファイル自体もUTF-8(できればBOM付き)で保存し直す必要があります。バッチファイルの保存エンコードとコードページの両方が一致して初めて正常動作します。VSCodeの場合は右下の文字コード → エンコード付きで保存 → UTF-8 with BOM を選択してください。
QShift-JISとUTF-8どちらで書けばよいですか?
A明確な理由がなければ Shift-JISが推奨です。日本語版Windowsのデフォルト設定で動き、古い環境との互換性も高いです。GitやLinux連携が必要な場合、絵文字など補助漢字を扱う場合はUTF-8 BOM付きを検討してください。なお、UTF-8 BOMなしはバッチでは避けてください。
Qfor /f でファイルを読み込むと文字化けします。
Afor /f はCP932前提で動作するため、UTF-8ファイルを直接読むと化けます。対象ファイルを Shift-JIS保存にするのが最も確実です。どうしてもUTF-8ファイルを読む必要がある場合は、PowerShellで一旦Shift-JISに変換してから for /f で読み込んでください。詳細は バッチでUnicodeファイルを扱えない原因と解決策 を参照。
Qecho で日本語を表示すると「?」になります。
Aecho が「?」になる場合は、バッチファイルがUTF-8で保存されているがコードページがCP932(デフォルト)のままになっています。バッチ冒頭に chcp 65001 >nul を追加するか、バッチをShift-JIS保存に変えてください。
Qchcp 65001 で動くようになったが set /p の入力がおかしくなります。
AこれはCP65001環境での set /p の既知の動作問題です。対策は PowerShellで入力を受け取る方法です:for /f "delims=" %%I in ('powershell -Command "Read-Host '入力:'"') do set INPUT=%%I のように書き換えてください。
QGitでバッチをコミットするとUTF-8になってしまいます。
AGitはファイルをそのまま保管しますが、.gitattributes の設定によってはCRLF/LF変換が入ることがあります。バッチの文字コード変換はGit自体は行いませんが、.gitattributes に *.bat text eol=crlf encoding=shift-jis を追加しておくと安全です。

