2011年1月28日金曜日

バッチファイルでIF文の条件式を書く時の注意点 - Windowsのコマンドプロンプト(bat,cmd)

Windowsコマンド。制御文と環境変数
○Windows XP
信頼性の高いバッチファイルを書く方法についてです。

IF文で変数を使う条件式を書く時は、条件式の左辺や右辺を「"」で括る事を、おすすめします。
そうしないと、変数の値が空の時に、左辺や右辺の値が空になって、文法エラーを起こす事があるからです。

o この動きは、コマンドプロンプト画面とは異なりますので、注意します。
o 問題を起こすのは、変数の値を「%」や「!」を使って表示する時です。
o 問題を起こさないのは
    + 変数の前後に普通の文字が入っている場合 = 必ず文字が残ります。
    + 値を数値と解釈する時も、大丈夫みたいです。例えば、「IF ERRORLEVEL 数値」構文


**** 問題が起こる書き方
o %1 が空の時、IF文の所で文法エラーになります = 途中で終了してしまいます。
--------
@echo off
if %1==ミクさん echo ミクさん。おはようございます。
echo 皆さん、おはようございます。
--------



**** 正しい書き方
o %1が空の時にも正しく動く書き方です。変数 %1 と値の両方を「"」で括るのがポイントです。
--------
@echo off
if "%1"=="ミクさん" echo ミクさん。おはようございます。
echo 皆さん、おはようございます。
--------



**** 確認したバージョン
o Windows XP Service Pack 3


==
関連ページ:
    ▼Windowsコマンド。制御文と環境変数▼ABC順
    ▼Windowsコマンド一覧▼ABC順
    ▼コマンドプロンプト画面
    ▼制作メモ
    > バッチファイル。IF文やFOR文の中で複数コマンドを書く時の注意点
    %変数の使い方
    環境変数の使い方。置換と部分文字列

バッチファイル。IF文やFOR文の中で複数コマンドを書く時の注意点 - Windowsのコマンドプロンプト(bat,cmd)

Windowsコマンド。制御文と環境変数
○Windows XP
IF 文や FOR 文の中で複数コマンドを実行したい時は、丸括弧(= 小括弧)を使うと便利です。
但し、次の時は、書き方を工夫する必要があります。
o IF 文や FOR 文の括弧内で環境変数の代入と参照を行いたい時
o 括弧内で、「"」に括られていない「)」を直接書きたい時


**** 問題となるパターン
o 括弧内で「"」に括られていない「)」を直接記述すると、文法エラーになります。
    + 全角の「)」は大丈夫です。
    + 変数の中に入っている「)」は大丈夫です。
o 次の2つの事を同時に行うと、コマンドプロンプトは予想外の値を返します。
    + 1つの丸括弧(= 小括弧)内で、環境変数に対して値を代入する
    + その括弧内において、代入した環境変数の値を参照する
o この時、参照した環境変数の値は、括弧内で代入する前の値となります。
    + 代入した値が有効になるのは、IF文(やFOR文)を抜けた直後からです。

--------
@echo off
set MIKU=ミクさん
if "%MIKU%"=="ミクさん" (
  set MIKU=ミク
  echo %MIKU%だよ
)
echo %MIKU%%MIKU%
--------

    + 予想は「ミクだよ」「ミクミク」
    + 結果は「ミクさんだよ」「ミクミク」


**** 問題となる原因
o コマンドプロンプトは、コマンドを1つずつ実行します。
o そして、IF文(やFOR文)は、括弧を含めて1つと解釈します。
o その結果、IF文(やFOR文)の中にある %環境変数% は、全て、IF文(やFOR文)を実行する直前の値で置き換わります。


**** 解決方法
o 3つの方法があります。
    + 参照と代入を別々の文に分けてしまう方法
    + CALL文を使う方法
    + 遅延環境変数を使う方法

** 参照と代入を別々の文に分けてしまう方法
--------
@echo off
set MIKU=ミクさん
if not "%MIKU%"=="ミクさん" goto XMIKU
set MIKU=ミク
echo %MIKU%だよ
:XMIKU
echo %MIKU%%MIKU%
--------

    + 結果は「ミクだよ」「ミクミク」
    + この書き方は、古いパソコンでも動きます。

** CALL文を使う方法
--------
@echo off
set MIKU=ミクさん
if "%MIKU%"=="ミクさん" call :x_call
echo %MIKU%%MIKU%
goto :eof

:x_call
set MIKU=ミク
echo %MIKU%だよ
goto :eof
--------

    + 結果は「ミクだよ」「ミクミク」
    + CALL先に限り、1文ずつ評価される状態になります。
    + 括弧の中から「echo %MIKU%だよ」の部分だけを CALL 文にする事も出来ます = 同じ結果になります。
    + この書き方は、古いパソコンで動くかどうかは分かりません。
    + CALL先をバッチファイルにして、goto :eofを使わなければ、古いパソコンでも動きます。

** 遅延環境変数を使う方法
o 遅延環境変数を使う場合、次の3点で書く方法がお手軽です。
    + setlocal をオプション付き
    + endlocal
    + 遅延評価したい環境変数は「%」の代わりに「!」
o 但し、環境変数の有効範囲が通常よりも狭くなっていますので、気を付けて使います。
    + setlocal の中で代入した環境変数の値は、endlocal やバッチファイルを抜けると元に戻ります。
--------
@echo off
setlocal enabledelayedexpansion
set MIKU=ミクさん
if "%MIKU%"=="ミクさん" (
  set MIKU=ミク
  echo !MIKU!だよ
)
echo %MIKU%%MIKU%
endlocal
--------

    + 結果は「ミクだよ」「ミクミク」
    + この書き方は、おそらく、Windows NT以前では動きません。
o この他に、コマンドプロンプト cmd.exe を遅延させるオプションを付けて呼び出し、その中で実行させる方法もあります。


**** 確認したバージョン
o Windows XP Service Pack 3


==
関連ページ:
    ▼Windowsコマンド。制御文と環境変数▼ABC順
    ▼Windowsコマンド一覧▼ABC順
    ▼コマンドプロンプト画面
    ▼制作メモ
    > %変数の使い方
    環境変数の使い方。置換と部分文字列
    環境変数の生存期間について
    +
    GOTO = 指定したラベルに移動する
    バッチファイルでif文の条件式を書く時の注意点
(2011年3月2日追加。FOR文対応と、CALLを使った回避方法)
(2011年1月30日追加。括弧内で「"」に括られていない「)」)