コマンドプロンプトで主にバッチファイルで使われる ifコマンドについてまとめてみる。

参考サイト→http://technet.microsoft.com/ja-jp/library/cc754335%28WS.10%29.aspx

○3つの基本構文

IF [NOT] ERRORLEVEL 番号 コマンド
IF [NOT] 文字列1==文字列2 コマンド
IF [NOT] EXIST ファイル名 コマンド

これら3つの基本形はMS-DOS初期のバージョンからWindows 7のコマンドプロンプトまで20年以上に渡ってサポートしているので、互換性の面ではまず心配ないだろう。

○基本例1

sample_program.exe
if errorlevel 1 echo プログラムが異常終了しました。
ver|find "Windows XP" > NUL
if not errorlevel 1 echo ご使用中のOSはWindows XPです。

多くのプログラムは終了時に終了コードというのを返す。ほとんどのプログラムは正常終了時に0、異常終了時に1以上の値を返すが、必ずしもそうと決まっているわけではない。
2行目はsample_program.exeが1以上の終了コードを返したらメッセージを表示する。
3,4行目はやや応用的で、findコマンドは指定した文字列を見つけると0を返した上でその文字が含まれる行を表示する。指定した文字列が見つからないと1を返す。つまり、verコマンドの実行結果に「Windows XP」が含まれていたら終了コード0を返す。ここでif errorlevel 0~ としてしまうと終了コードが0以上の時にコマンドを実行するので、意図したとおりに動作しない。if not errorlevel 1 つまり終了コードが1以上でない = 0以下のとき、とすることで正しく動作する

コマンドプロンプトでは代わりにERRORLEVEL環境変数を用いることで後述の基本例3のように比較演算子を使って条件分岐が可能。MS-DOSやWin9xのMS-DOSプロンプトではERRORLEVEL変数をサポートしていない。

○基本例2

set abc=test
if %abc%==test echo 変数abcと"test"は一致しています。
if "%def%"=="test test" echo 変数defと"test test"は一致しています。

「abc」という変数に「test」という文字列を入れ、2行目で変数abcの内容と「test」を比較している。
変数がスペースを含む、もしくは含む可能性がある場合は3行目のようにする。
引用符は必須ではないが、比較対象の変数が空だったりすると構文エラーになることがあるので常に引用符を付けておいたほうがいい。
引用符も文字列比較の対象に入るので、両方の比較対象に引用符を付けないと一致したことにならない。

○基本例3

if exist C:¥file.txt echo ファイル C:¥file.txtは 存在します。
if exist C:¥dir¥NUL echo ディレクトリ C:¥dir は存在します。

コマンドプロンプトではファイルだけでなくフォルダパスも指定できるが、MS-DOSやMS-DOSプロンプトではサポートしていない。
ただし、例の2行目のようにファイル名としてNULを指定することでフォルダーの有無を確認できる。

○コマンド拡張機能有効時に使える構文

IF [/I] 文字列1 比較演算子 文字列2 コマンド
IF CMDEXTVERSION 番号 コマンド
IF DEFINED 変数 コマンド

これらはコマンドプロンプトでのみ使用可能で、MS-DOSやMS-DOSプロンプトではサポートしていない。
コマンド拡張機能とはWindows NT系に搭載されているコマンドプロンプト(cmd.exe)で新たに拡張された機能で、具体的には、バッチファイルで使うIF、FOR、SETコマンドなどの追加機能のこと。便利な機能が使えるようになった反面、新しい機能によってこれまでのMS-DOS/Win9x用バッチファイルが正しく動作しないことがある。そのため、コマンド拡張機能は標準では有効になっているが、レジストリの設定やSETLOCALコマンドなどによってこれを無効にできる。

○基本例4

set num1=30
set num2=20
if %num1% GTR %num2% (echo %num1%>%num2%
) else if %num1% EQU %num2% (echo %num1%=%num2%
) else if %num1% LSS %num2% echo %num1%<%num2%

例はnum1とnum2の数字の大小を調べている。
比較演算子はWindows 2000以降では小文字でもよいが、NT4.0以前では大文字でないとコマンドを受け付けない。
括弧については後ほど補足。

○基本例5

if not cmdextversion 2 echo このバージョンのWindowsではバッチファイルを正しく実行できない可能性があります。

あまり使う機会がない構文。使い方はerrorlevelと同じ。
ちなみにコマンド拡張機能のバージョンはWindows NT4.0までが1、Windows 2000、XP、Vista、7は2である。

○基本例6

if defined windir echo Windowsフォルダは%windir%にあります。

これもそれほど使う機会はない。
コマンド拡張機能を使わずに環境変数が定義されているかどうかを確認するには、

if not "%var%"=="" echo 環境変数 var は定義されています。

とする。

○応用例1 : 剰余を計算する(数値比較、複数行の条件分岐)

set num1=24
set num2=10
if %num2% EQU 0 (
echo 0除算エラーです。
goto :eof
) else if %num2% LSS 0 (
echo 負の値は指定できません。
goto :eof
)
set /a ans=%num1%%%%num2%
if errorlevel 1 (
echo 演算処理に失敗しました。
) else if %ans% EQU 0 (
echo 余りはありません。
) else (
echo %num1%÷%num2%の余りは%ans%です。
)

例はnum1をnum2で割った余りを求めている。
括弧でくくることで条件分岐の中で複数のコマンドを実行することができるが、この形はコマンドプロンプトでのみ使用可能。
if文の中にif文を含める 入れ子構造 も処理してくれる。
elseは独立したコマンドではなくifコマンドの構文に含まれるため、if文と同じ行に置く必要がある。
この例ではelseの前に終わり括弧を置くことで、if文がこの行まで続くことを示している。

1つ注意点があって、先に述べたようにプロンプトはif文の括弧の始まりから終わりまでを1つの文として一括で読み取り解釈する。
つまりif文の途中で変数の値を変えて、さらにそのif文中でその変数を使った処理をしようとすると、意図したとおりにならないことがある。
この問題は「遅延環境変数の展開」機能を利用することで解決できる。

○応用例1+ : 遅延環境変数の展開を使った応用例1の簡略版

setlocal enabledelayedexpansion
set num1=24
set num2=10
if %num2% EQU 0 (echo 0除算エラーです。
) else if %num2% LSS 0 (echo 負の値は指定できません。
) else (
set /a ans=%num1%%%%num2%
if errorlevel 1 (echo 演算処理に失敗しました。
) else if !ans! EQU 0 (echo 余りはありません。
) else echo %num1%÷%num2%の余りは!ans!です。
)
endlocal

試しにこの例の!ans!を%ans%に戻して実行してみると、「0 の使い方が誤っています。」というエラーが表示される。
これはプロンプトが4~11行目を解釈した時点では変数ansに値が設定されておらず、
9行目で「if  EQU 0 ~」という誤った構文のコマンドを実行したためである。
変数num1、num2については、if文に入る前の2、3行目で設定しているためエラーにはならない。

○応用例2 : 指定したフォルダ内のフォルダ数を取得 (入力メソッド、数値比較)

:retry
echo フォルダパスを入力してEnterキーを押してください。
echo 何も入力せずにEnterキーを押すとこのバッチファイルを終了します。
set fddir=
set /p fddir=^>
if not defined fddir goto :eof
if not exist %fddir% goto retry
>folderlist.txt dir /ad /b %fddir%
for /F "delims=" %%a in ('find /v /c "" folderlist.txt') do set fdcount=%%a
if %fdcount:~27% EQU 0 (echo %fddir%内にサブフォルダはありません。) else echo %fddir%内にサブフォルダは%fdcount:~27%個あります。
del folderlist.txt

6行目は入力メソッドで何も入力しなかったときに終了。
7行目は不正なパスが入力された時に再度入力要求。
10行目で数字の比較。
ちなみに4行目は一見意味がないように見えるが、1度目で不正なパスを入力した後、2度目以降の入力メソッドで終了できるために必要になる。


※コメント欄が表示されない場合はdisqusについてJavascriptが有効であることを確認して下さい。コメントはスパム防止フィルターによる承認制のため、投稿してもすぐに反映されない場合があります。

管理人 : Akamaki (akm)

は、PCとVTuberに夢中になっている電気技術者です。

私はレトロコンピューティングの愛好家ですが、そのようなリグはもう収集していません。

私の活動はトップページで見ることができます。読んでくれてありがとう!