【bat】バッチファイルでy/n確認による処理分岐を実現する方法完全ガイド|set /p・CHOICE・デフォルト・タイムアウトまで

「本当に削除しますか?(y/n)」「本番デプロイを続行しますか?」――バッチファイルで操作前に確認を挟むことで、誤操作による取り返しのつかないミスを防げます。

本記事では set /p による基本形から CHOICE コマンドを使ったよりシンプルな実装、デフォルト値・タイムアウト付きの応用パターンまで体系的に解説します。

スポンサーリンク

目次

  1. 方法1:set /p で y/n を入力させる
  2. 方法2:CHOICE コマンドで y/n を選択させる
  3. 方法3:デフォルト値付き確認(Enter で自動承認)
  4. 方法4:タイムアウト付き自動承認(CHOICE /T)
  5. 方法比較表
  6. 実践例A:ファイル削除前の確認ダイアログ
  7. 実践例B:本番デプロイ前の複数確認
  8. 実践例C:タイムアウト付き自動処理
  9. 落とし穴5選
  10. FAQ
  11. まとめ

方法1:set /p で y/n を入力させる

set /p はプロンプトを表示してユーザーのキーボード入力を変数に格納するコマンドです。if /i と組み合わせて y/n を判定します。

@echo off
setlocal

:ask
set "INPUT="
set /p "INPUT=続行しますか? [y/n]: "

if /i "%INPUT%"=="y" (
    echo はいを選択しました。処理を続行します。
    goto :main
)
if /i "%INPUT%"=="n" (
    echo いいえを選択しました。処理を中止します。
    exit /b 0
)
echo y または n を入力してください。
goto :ask

:main
echo 処理を実行中...
endlocal

ポイント:

  • set "INPUT=" で毎回変数を初期化する(空Enterでも前回値が残らないようにする)
  • /i フラグで大文字・小文字を区別しない(Y と y を同等に扱う)
  • 想定外の入力は goto :ask でループして再入力を促す

方法2:CHOICE コマンドで y/n を選択させる

CHOICE はキーを1つ押すだけで選択できる専用コマンドです。Enterが不要なため操作が直感的で、結果は ERRORLEVEL で取得します。

@echo off
setlocal

choice /c YN /m "続行しますか"

if ERRORLEVEL 2 (
    echo いいえを選択しました。処理を中止します。
    exit /b 0
)
if ERRORLEVEL 1 (
    echo はいを選択しました。処理を続行します。
)

echo 処理を実行中...
endlocal

CHOICEERRORLEVEL は選択肢の順番に対応します。/c YN の場合:

キー ERRORLEVEL
Y 1
N 2

重要: if ERRORLEVEL N は「N 以上なら真」という意味のため、大きい値から順に判定してください。N→Y の順(降順)で if ERRORLEVEL を書くのが正しいパターンです。

CHOICE コマンドの主なオプション

オプション 意味
/c キー一覧 受け付けるキーを指定 /c YN
/m メッセージ プロンプト文字列 /m "続行しますか"
/d キー タイムアウト時のデフォルト /d Y
/t 秒数 自動選択までの待機秒数 /t 10
/n キー一覧を表示しない /n

方法3:デフォルト値付き確認(Enter で自動承認)

set /p でEnterのみ入力された場合にデフォルト値を適用するパターンです。「[Y/n]」のように大文字で示したキーがデフォルトであることを視覚的に伝えます。

@echo off
setlocal

:: デフォルト=Y(Enterだけ押した場合にYとして扱う)
set "INPUT=Y"
set /p "INPUT=続行しますか? [Y/n]: "

if /i "%INPUT%"=="n" (
    echo キャンセルしました。
    exit /b 0
)

echo 続行します。処理を実行中...
endlocal

set "INPUT=Y" で先にデフォルト値を設定しておくと、空Enter時も Y が入ったままになります。n が入力された場合だけキャンセル処理を行えばOKです。

方法4:タイムアウト付き自動承認(CHOICE /T)

一定時間内に回答がなければデフォルト値で自動選択するパターンです。自動化スクリプトで人が監視しているときは確認を挟みつつ、無人実行時は自動承認させたい場合に有効です。

@echo off
setlocal

echo 10秒以内に回答がない場合、自動的に Y が選択されます。
choice /c YN /m "続行しますか" /t 10 /d Y

if ERRORLEVEL 2 (
    echo いいえを選択しました。処理を中止します。
    exit /b 0
)
if ERRORLEVEL 1 (
    echo はい(またはタイムアウト)を選択しました。処理を続行します。
)

echo 処理を実行中...
endlocal

タスクスケジューラや無人バッチでもタイムアウト後に自動続行するため、ハングアップしません。

方法比較表

方法 入力方法 デフォルト値 タイムアウト 主な用途
set /p 文字列+Enter ○(変数初期値で設定) × 柔軟な入力・複数文字対応
CHOICE キー1つのみ ○(/d オプション) ○(/t オプション) シンプルなy/n・自動化

インタラクティブ性と確実性を求めるなら CHOICE が推奨です。複数文字の入力や日本語プロンプトが必要な場合は set /p を使います。

実践例A:ファイル削除前の確認ダイアログ

重要なファイルを削除する前に確認を挟む定番パターンです。誤操作によるデータ消失を防ぎます。

@echo off
setlocal

set TARGET=C:\Logs\old_data

if not exist "%TARGET%" (
    echo [INFO] 削除対象が見つかりません: %TARGET%
    exit /b 0
)

echo 以下を削除します:
echo   %TARGET%
echo.

choice /c YN /m "本当に削除しますか"

if ERRORLEVEL 2 (
    echo キャンセルしました。
    exit /b 0
)
if ERRORLEVEL 1 (
    echo 削除中...
    if exist "%TARGET%\*" (
        rd /s /q "%TARGET%"
    ) else (
        del /f /q "%TARGET%"
    )
    echo 削除完了。
)
endlocal

削除前にパスを表示して視認できるようにしています。フォルダの場合は rd /s /q、ファイルの場合は del /f /q で処理を切り替えています。

実践例B:本番デプロイ前の複数確認

本番環境へのデプロイ前に複数の確認を順番に行い、全てYでないと処理が進まないパターンです。

@echo off
setlocal

echo ========================================
echo  本番デプロイ確認
echo ========================================
echo.

:: 確認1: バックアップ済みか
choice /c YN /m "[1/3] バックアップは完了していますか"
if ERRORLEVEL 2 (
    echo バックアップを先に実施してください。中止します。
    exit /b 1
)

:: 確認2: テスト済みか
choice /c YN /m "[2/3] テスト環境での確認は完了していますか"
if ERRORLEVEL 2 (
    echo テスト確認後に再実行してください。中止します。
    exit /b 1
)

:: 確認3: 最終確認
choice /c YN /m "[3/3] 本番環境へのデプロイを実行しますか"
if ERRORLEVEL 2 (
    echo デプロイを中止しました。
    exit /b 0
)

echo.
echo すべての確認が完了しました。デプロイを開始します。
echo [%date% %time%] デプロイ開始
echo 処理中...
endlocal

各確認で N を選んだ場合に即座に処理を中止し、適切なメッセージを表示します。exit /b の使い方と組み合わせることで、サブルーチン内から正しく終了できます。

実践例C:タイムアウト付き自動処理

定期実行スクリプトで、人が監視しているときは確認を挟み、無人実行時(タスクスケジューラ等)では自動続行するパターンです。

@echo off
setlocal

set LOG=C:\Logs\auto-task.log
echo [%date% %time%] スクリプト開始 >> %LOG%

:: インタラクティブ実行かどうか判定(引数 /auto が渡された場合は確認スキップ)
if /i "%1"=="/auto" (
    echo [AUTO] 自動実行モード。確認をスキップします。
    goto :do_task
)

:: 10秒待機・デフォルトY
echo 処理を開始します。キャンセルする場合は N を押してください。
choice /c YN /m "10秒後に自動的に開始します" /t 10 /d Y

if ERRORLEVEL 2 (
    echo キャンセルしました。
    echo [%date% %time%] キャンセル >> %LOG%
    exit /b 0
)

:do_task
echo 処理を実行中...
echo [%date% %time%] 処理実行 >> %LOG%
echo 完了。
echo [%date% %time%] 完了 >> %LOG%
endlocal

cleanup.bat /auto で実行すると確認ダイアログをスキップして自動実行、引数なしで実行すると10秒のカウントダウン付きで確認します。

落とし穴5選

落とし穴1:set /p で変数を初期化しないと空Enter時に前回値が残る

set /p で変数を初期化せずに使うと、ユーザーがEnterだけ押した場合に変数の値が更新されず、前回の入力値がそのまま残ります。ループ内では毎回 set "INPUT=" で必ずリセットしてください。

:: NG: INPUT が前回値のまま残る
:ask
set /p "INPUT=続行しますか? [y/n]: "

:: OK: 毎回リセット
:ask
set "INPUT="
set /p "INPUT=続行しますか? [y/n]: "

落とし穴2:/i フラグを忘れると大文字 Y/N が受け付けられない

if "%INPUT%"=="y"(/i なし)では小文字の y のみ一致します。ユーザーが大文字 Y を入力した場合に else に落ちてしまいます。if /i を必ず付けてください。

:: NG: "Y" を入力されると else に落ちる
if "%INPUT%"=="y" (echo はい) else (echo いいえ)

:: OK: 大文字・小文字どちらも受け付ける
if /i "%INPUT%"=="y" (echo はい) else (echo いいえ)

落とし穴3:CHOICE の ERRORLEVEL は降順で判定する

if ERRORLEVEL N は「N 以上なら真」という意味です。昇順(1→2)で書くと、ERRORLEVEL=2 のときに if ERRORLEVEL 1 も真になり誤動作します。必ず大きい値(2)から先に判定してください。

:: NG: 昇順で書くと ERRORLEVEL=2 でも最初の if が真になる
if ERRORLEVEL 1 echo Y が選ばれました
if ERRORLEVEL 2 echo N が選ばれました

:: OK: 降順(大きい値から)で判定
if ERRORLEVEL 2 echo N が選ばれました
if ERRORLEVEL 1 echo Y が選ばれました

落とし穴4:CHOICE はリダイレクトやパイプ経由では動かない

choice はコンソールに直接接続されているときのみ動作します。choice < input.txt のようにリダイレクトで入力を渡すことはできません。自動テストや入力ファイルを使う場合は set /p を使ってください。

落とし穴5:set /p でクォートなし変数を使うと空文字でエラー

変数参照を %INPUT%(クォートなし)で使うと、変数が空の場合に if ==y となり構文エラーになります。常に "%INPUT%" のようにクォートで囲んでください。

:: NG: INPUT が空のとき「if  ==y」になり構文エラー
if %INPUT%==y echo はい

:: OK: クォートで囲む
if "%INPUT%"=="y" echo はい

FAQ

Y/N 以外の選択肢(3択以上)を実装したい
CHOICE /c ABC のように複数キーを指定できます。ERRORLEVEL は A=1, B=2, C=3 に対応します。set /p を使えば任意の文字列入力も受け付けられます。
プロンプトに日本語を使うと文字化けする
バッチファイルの文字コードがShift-JISの場合、コマンドプロンプトのコードページと一致していれば日本語表示できます。文字化けする場合は chcp 932(Shift-JIS)または chcp 65001(UTF-8)をスクリプト冒頭に追加してください。ただしchcp 65001は一部環境で問題が出ることがあります。
確認結果をログファイルに記録したい
echo [%date% %time%] 確認: %INPUT% >> log.txt のように確認後にログ出力を追加します。CHOICEの場合はERRORLEVELを変数に保存してからログに記録してください。
サブルーチン(call)から呼んでも正しく動きますか?
動作します。ただし CHOICE の後 ERRORLEVEL を参照する前に別のコマンドを実行すると値が上書きされます。ERRORLEVEL を変数に退避してから判定してください。
set /a RESULT=%ERRORLEVEL% のように保存します。
Yを選んだらラベルにジャンプ、Nは終了という書き方は?
goto と組み合わせます。if ERRORLEVEL 1 goto :do_task のように書けます。goto / ラベルの使い方はgoto・ラベルの完全ガイドを参照してください。
タスクスケジューラで実行するときは確認を自動スキップしたい
引数で実行モードを切り替える方法(実践例Cのパターン)か、CHOICE /t 0 /d Y(待機0秒・デフォルトY)でタイムアウトを0に設定する方法が使えます。

まとめ

状況 推奨方法
シンプルにy/nだけ確認したい CHOICE /c YN
タイムアウト・デフォルト値が必要 CHOICE /t /d
Enter で続行・n でキャンセルしたい set /p(デフォルト値付き)
自動実行と対話実行を切り替えたい 引数判定 + CHOICE /t
3択以上の選択が必要 CHOICE /c ABC…

遅延展開変数を使ったループ内での判定についてはsetlocal enabledelayedexpansion 完全ガイドも参照してください。