まほろば技術パーク

@komeshogun's InfoTech MEMO

FOR文内でユーザ応答に応じて処理を実行するwindowsバッチ

■概要
BATファイルが配置されているディレクトリに存在するSQLファイルをファイル名の昇順ですべて実行する。

■課題
FOR文内でユーザ応答を行い、実行確認する箇所で詰まった。
なぜかIF文内に入らずに、EXEC_FLGが空文字になってしまった。

SETLOCAL ENABLEDELAYEDEXPANSION
SET /P EXEC_FLG="続行しますか?(Y):"
  IF /I "!EXEC_FLG!"=="Y" ()

■解決方法
WindowsバッチではFOR文やIF文に入る前に変数が展開されるらしく
FOR文に入る前にSETしとかないといけない。

REM 遅延環境変数の展開オプション
SETLOCAL ENABLEDELAYEDEXPANSION

さらに以下のようにしておかないとFOR文内でインクリメントしたのが
使えず0のままとなっていた。

ENDLOCAL && SET CNT=%CNT% && SET FILE_NUM=%FILE_NUM%

■小ネタ
①ユーザ応答の構文には、「/P」オプションをつける。

SET /P DB_INFO="接続先情報を入力して下さい(例:user/pass@schema):"

②大文字・小文字を区別させないためには、「/I」オプションを付ける。
IF文の比較時にはダブルクォーテーションを付けないと構文エラーとなる。

IF /I NOT "%CONTINUE_FLG%"=="Y" GOTO :END

③数値を扱うためには「/A」オプションをつける。

SET /A FILE_NUM=0

④現在のフォルダに移動する

PUSHD %0\..

⑤フォルダに存在するSQLファイル分処理を繰り返す。
/on:名前順、/od:日付順(古い順)、/os:サイズ順(小さい順)

FOR /f "delims=;" %%I IN ('dir /b /on *.sql') DO (

■サンプルプログラム

@ECHO OFF	

ECHO 本バッチファイルと同一ディレクトリに存在するSQLファイルをすべて実行します。
ECHO 処理順はSQLファイル名順に実行されます
SET /P DB_INFO="接続先情報を入力して下さい(例:user/pass@schema):"

ECHO 接続先:SQLPLUS %DB_INFO%
SET /P CONTINUE_FLG="接続先が正しいか確認してください。続行しますか?(Y):"

IF /I NOT "%CONTINUE_FLG%"=="Y" GOTO :END

REM 実行フラグ
SET EXEC_FLG=

REM 処理対象ファイル件数
SET /A FILE_NUM=0

REM 処理件数カウンター
SET /A CNT=0

REM 遅延環境変数の展開オプション
SETLOCAL ENABLEDELAYEDEXPANSION

REM 現在のフォルダに移動。
PUSHD %0\..

REM フォルダに存在するSQLファイルをすべて実行する。
REM /on:名前順、/od:日付順(古い順)、/os:サイズ順(小さい順)
FOR /f "delims=;" %%I IN ('dir /b /on *.sql') DO (
  ECHO ============================================
  SET /A FILE_NUM=FILE_NUM+1
  ECHO %DATE% %TIME% !FILE_NUM!件目:[SQLPLUS %DB_INFO% @%%I]を実行します。

  SET /P EXEC_FLG="続行しますか?(Y):"

  IF /I "!EXEC_FLG!"=="Y" (
    REM Y(小文字も可)が入力された場合、処理を実行する。
    SQLPLUS %DB_INFO% @%%I
    SET /A CNT=CNT+1
    ECHO %DATE% %TIME% [SQLPLUS %DB_INFO% @%%I]を完了しました。
 )
)
ENDLOCAL && SET CNT=%CNT% && SET FILE_NUM=%FILE_NUM%

ECHO ============================================
ECHO %DATE% %TIME% すべてのSQLが完了しました。実行件数:%CNT%件(/%FILE_NUM%件中)

PAUSE

EXIT

:END

EXIT