【bat】バッチファイルで日本語が文字化けする完全原因解説と解決策ガイド|コードページ・保存エンコード・for /f・ログ出力まで

バッチファイルで日本語を扱うと、文字化けが発生することがあります。原因は単純なようで意外に多層的で、「バッチファイルの保存エンコーディング」「コマンドプロンプトのコードページ(文字コード設定)」「コマンドの挙動の違い」が複雑に絡み合っています。本記事では文字化けが起きる仕組みを根本から解説し、場面ごとの確実な解決策を示します。

この記事でわかること

  • コードページ(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保存が「基本」だが限界もある
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 の落とし穴

chcp 65001 には以下の既知の問題がある

  1. echo が正常に動かない場合がある: Windows の古いバージョンや特定の環境では chcp 65001 にしても echo が文字化けすることがあります。
  2. set /p の入力が壊れることがある: ユーザー入力を受け取る set /p で 入力値が正しく格納されないケースがあります。
  3. for /f がShift-JISファイルを正しく読めない: コードページをUTF-8に変えても for /f はバイト列をそのまま処理するため、Shift-JISファイルの内容が化けることがあります。
  4. 一部のコマンド出力が化ける: dirnet などの出力が 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なし
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 を追加しておくと安全です。