Programming Field

If - DOS/コマンドプロンプト コマンド一覧

バッチファイル内で、条件分岐の処理を行います。

構文

以下の7つうち1つ(4つ目以降は拡張構文)を使います。

if [not] errorlevel <number> <command-line> [else <command-line>]
if [not] exist <file-name> <command-line> [else <command-line>]
if [not] <string1>==<string2> <command-line> [else <command-line>]
if /I [not] <string1>==<string2> <command-line> [else <command-line>]
if [/I] [not] <string1> <operator> <string2> <command-line> [else <command-line>]
if [not] defined <variable-name> <command-line> [else <command-line>]
if [not] cmdextversion <number> <command-line> [else <command-line>]

オプション一覧

not 次の来る条件文が「該当しない」(「偽」である) かどうかで処理を決定します。not を付けると該当しない場合に後ろの処理 (<command-line>) が実行されます。
errorlevel <number> 直前のプログラムが返した終了コードをチェックします。<number> には数値を指定します。終了コードが <number> 以上の値のとき、<command-line> が実行されます。
exist <file-name>

指定したファイルが存在するかどうかをチェックします。<file-name> にはファイル名を指定します (ドライブ・パスも含めることが出来ます)。ファイル <file-name> が存在するとき、<command-line> が実行されます。

<file-name> がディレクトリのときの動作(ディレクトリが存在するかどうかの判定)はOSによって異なるので注意してください。

<string1>==<string2>

2つの文字列の値が等しいかどうかをチェックします。<string1><string2> には文字列を指定します。通常は一方、または両方に(「%」を使って)環境変数を指定し、その値をチェックします。<string1><string2> が等しいとき、<command-line> が実行されます。

文字列の比較は大文字・小文字が区別されます。また、文字列にクオーテーションマークは必要ありません。なお、「==」の前後にスペースを含むことはできます(比較には影響しません)。「文字列比較」もご覧ください。

[MS-DOS, Windows 95/98/Me] クオーテーションマークで括った場合でも、文字列(<string1><string2> の部分)にコンマ「,」やスペース、等号「=」、セミコロン「;」などは使用できません。

<command-line>

条件に該当するときに実行するコマンドを指定します。コマンドには環境変数や引数を含めることが出来ます。

[Windows NT 系]( )」 を用いてコマンドを複数行に分割することができます。ただし、一連のコマンドはひとまとまりとして処理されるため、「%」の展開は ( ) 内すべてを対象に先に行われます。

else <command-line>

[Windows NT 系のみ] 条件に該当しなかったとき (not があるときは条件に該当したとき) に実行するコマンドを指定します。コマンドには環境変数や引数を含めることが出来ます。

else 以下の <command-line> にも「( )」を使用することができますが、else の前に「( )」を用いた場合は閉じ括弧の直後に(スペースを挟んで)「else」を書く必要があります。(後述の解説参照)

/I [Windows NT 系] [拡張機能] 「==」や下記 <operator> で比較を行う際、文字列の大文字・小文字を区別しません。
<operator> [Windows NT 系] [拡張機能] 比較に用いる演算子を以下の中から指定します(「==」も含みます)。なお、<string1><string2> が数字のみの文字列の場合は数値として、数字以外の文字が含まれている場合は文字列として比較が行われます。
EQU<string1><string2> が等しいかどうか
NEQ<string1><string2> が等しくないかどうか
LSS<string1><string2> より小さいかどうか
LEQ<string1><string2> より小さい、または等しいかどうか
GTR<string1><string2> より大きいかどうか
GEQ<string1><string2> より大きい、または等しいかどうか
defined <variable-name> [Windows NT 系] [拡張機能]<variable-name>」に指定した名前の環境変数が存在するかどうかをチェックします。<variable-name> の環境変数が存在するとき、<command-line> が実行されます。<variable-name> には「%」文字は指定せず、名前を直接記述します(大文字・小文字は区別しません)。
cmdextversion <number>

[Windows NT 系] [拡張機能] コマンド拡張機能の内部バージョン(CMDEXTVERSION環境変数の値です)が「<number>」の値以上かどうかをチェックします。

なお、拡張機能が無効になっている場合は常に偽となり、コマンドは実行されません。(MS-DOS, Windows 95/98/Me では構文エラーになります。)

解説

If使用例

このコマンドは、バッチファイルで条件分岐を行いたいときによく用いられるコマンドです(Goto<command-line> によく用いられます)。このコマンド自体が条件分岐を行うため、実行するコマンドが1つだけの場合などは、Goto は必ずしも行う必要がありません。

errorlevel

errorlevel による終了コードの評価(比較)は、説明にあるように、指定した数値以上の値であればヒットとなるため、複数の終了コードをチェックしたい場合は、数値の大きい順に終了コードをチェックしていく必要があります。例えば、

if errorlevel 1 goto label1
if errorlevel 2 goto label2
if errorlevel 3 goto label3
if errorlevel 4 goto label4
.
.
.

のコードでは、終了コードが 0 でなかった場合(1 以上の場合)は、1 だろうと 4 だろうとラベル「label1」にジャンプしてしまいます。よって正しくは

if errorlevel 4 goto label4
if errorlevel 3 goto label3
if errorlevel 2 goto label2
if errorlevel 1 goto label1
.
.
.

とします。なお、一般的なプログラムは正常終了した場合に終了コードを0に設定するため(Choiceなどの例外もあります)、「if errorlevel 1 goto OnError」と記述すればほとんどの場合でプログラムにエラーが発生したときの処理を分岐させることができます。

[Windows NT系] errorlevelの確認に負の値(マイナスの値)を用いることもできます。

[Windows NT系] [拡張機能] 拡張機能が有効になっている場合、この構文の代わりに下記の文字列比較構文を用い、「ERRORLEVEL」環境変数を使用して値の比較を行うことができます。例えば以下のように書くことができます。

rem 終了コードが2のときジャンプ
if "%ERRORLEVEL%"=="2" goto label2
rem 終了コードが1以下のときジャンプ
if "%ERRORLEVEL%" LEQ "1" goto label0_1
.
.
.

exist

exist はファイルが存在するかどうかをチェックします。ファイルは隠しファイルやシステムファイルであっても、このコマンドで存在を確認することが出来てしまいます。

ディレクトリの存在が確かめられるかどうかは、Windows 95 と XP では挙動が異なるため、注意が必要です。(実際にテストするには、例えばプロンプト上で「if exist C:\WINDOWS echo ok」などと入力して「ok」と表示されれば、ディレクトリに対しても使用できることを表します。)

なお、NULファイルを用いることで、MS-DOS・Windows 9x・Windows NT系すべてでディレクトリの存在確認(およびファイルではなくディレクトリかどうかの確認)を行うことができます。

if exist X:\Hoge\NUL echo ok

このコマンドを実行すると、「X:\Hoge」がディレクトリとして存在する場合に「ok」が画面に出力されます。(X:\Hoge が存在しない、あるいはディレクトリではない場合には「echo ok」が実行されません。)

文字列比較

文字列比較は、環境変数の値やバッチファイルに指定された引数を評価(比較)するのによく使います。環境変数や引数の値は「%」を使って取得できる(環境変数TEMPなら「%TEMP%」、「2番目の引数」なら「%2」← Shift コマンドも参照)ので、上記の <string1><string2> にそれらを指定します。

上記にあるように、クオーテーションマークは必要ありません。以下のコードもご覧ください。

if "test"=="test" echo 1
if "test==test" echo 2
if test"==test" echo 3
if !test==!test echo 4
if !%1==!hello echo 5

このコードで出力される数値は 1, 3, 4 です。また、バッチファイルの引数に「hello」が指定されている場合(%1 が hello である場合)は、数値 5 も出力されます。

ただし、環境変数の値を比較する場合、その環境変数が空である場合を考慮するとクオーテーションマーク(またはその他文字や記号)が必要になる場合があります。これは、比較対象の文字列に何も指定されていない場合は構文エラーとなるためです。例えば、

if %foo%==foo echo ok

と書いた場合、環境変数「foo」が空であると構文エラーとみなされます。これを防止するには、

rem -- 以下のいずれでも可
if "%foo%"=="foo" echo ok
if $%foo%==$foo echo ok

のような書き方をする必要があります。

※ 同様に、文字列が空であるかどうかをチェックする場合もクオーテーションマークなどが必要になります。

任意の比較

[Windows NT 系] [拡張機能] 「LSS」や「GEQ」など、「==」以外の演算子を用いて文字列または数値の比較を行い、それによって後続の処理を変えることができます(演算子は「構文」参照)。比較対象がともに数値になっている場合は数値として比較を行いますが、一方が数値ではない文字列の場合はアルファベットが辞書式順序に従って大きいか小さいかの比較が行われます。ただし「/I」が指定されていない場合、まずは大文字・小文字を区別しない比較が行われ、そこで一致する場合に「小文字の方が大文字より小さい」として比較を行います。

※ アルファベットと数字以外の文字についてはどの順序で比較されるか不明です。

rem -- 文字列が一致する場合
if "aaa" EQU "aaa" echo 1
rem -- 大文字・小文字のみ一致しない場合
if "aaa" EQU "Aaa" echo 2
rem -- 「/I」があり、大文字・小文字のみ一致しない場合
if /i "aaa" EQU "Aaa" echo 3
rem -- 「より小さい」比較で文字列が一致する場合
if "aaa" LSS "aaa" echo 4
rem -- 「より小さい」比較で文字列が一致しない場合(「a」<「b」)
if "aba" LSS "aaa" echo 5
rem -- 「より小さい」比較で文字列が一致しない場合、辞書式順序の適用(「ab」<「ba」)
if "aba" LSS "baa" echo 6
rem -- 「より小さい」比較で文字列が一致しない場合(「b」<「c」)
if "aab" LSS "aac" echo 7
rem -- 「より小さい」比較で文字列が大文字・小文字のみ一致しない場合(「a」<「A」)
if "aaa" LSS "Aaa" echo 8
rem -- 「より小さい」比較で大文字・小文字よりも文字違いを優先する場合1(「A」<「b」)
if "baa" LSS "Aaa" echo 9
rem -- 「より小さい」比較で大文字・小文字よりも文字違いを優先する場合2(「Aa」<「ab」)
if "aba" LSS "Aaa" echo 10
rem -- 「数値」として扱うことができるのは整数のみ(小数は認識されない)
if "1" EQU "1.0" echo 11

この例では「1」「3」「6」「7」「8」が出力されます。

else

[Windows NT 系] 条件に当てはまる場合と当てはまらない場合それぞれでコマンドを実行したい場合に使用します。「else」は「if」を書いた行と同じ行に書く必要がありますが、コマンドラインは「コマンドの末尾を改行またはブロックの終端にする」必要があるため、以下のように「( )」を用いて記述する必要があります。

if /i "%~1"=="/delete" (del mydata.dat) else (echo Not deleted.)

(括弧「( )」を用いないと「"%~1"=="/delete"」以降が「del mydata.dat else echo Not deleted.」というコマンドラインに解釈されてしまいます。)

その他

[Windows NT 系] 条件に当てはまる際に実行するコマンドを1つではなく複数実行したい場合は、それらのコマンドを「( )」で囲んで複数行に分けて記述します。例えば、

if "test"=="test" (
    echo 1
    echo 2
)

を実行すると、2行にわたって「1」と「2」が出力されます。なお、環境変数の展開はIfの処理が行われる際に括弧内も含めてすべて行われるため、括弧内でSetを用いている場合は注意が必要です(Setlocalおよび「!」の説明も参照)。

else を用いる場合は、最初の閉じ括弧の直後に else を記述します。閉じ括弧の後に改行を入れることはできません(「( )」全体がひとまとまりの(改行されていない) <command-line> になるため)。

if "test"=="test" (
    echo 1
    echo 2
) else (
    echo 3
    echo 4
)

サンプル 1 (バッチファイル)

@echo off
:Begin
echo MySetup.ini のファイルがある CD をドライブ E に入れてください。
echo CD を入れたら何かキーを押してください。キャンセルするには
echo Ctrl+C を入力してください。
pause > NUL
if exist E:\MySetup.ini goto Finish
echo MySetup.ini が見つかりません。
goto Begin
:Finish

ファイル MySetup.ini が入った CD を E ドライブに挿入するまで終えないバッチファイルです (CD ドライブを E と仮定)。

サンプル 2 (バッチファイル)

@echo off
foo.exe "%1"
if "%errorlevel%"=="255" echo 致命的なエラーが起こりました。
if "%errorlevel%"=="23" echo '%1' に対して何かが起こりました。

[Windows NT 系] [拡張機能] プログラム foo.exe にバッチファイルの1番目の引数を渡して実行し、その終了コードを文字列比較でチェックしています。If errorlevel では「~以上」の判定しか出来ないので、Windows NT 系の拡張機能では errorlevel を環境変数として扱うことにより、「~と等しい」の判定が行えるようになっています。

※ If errorlevel を使ったサンプルは Choice コマンドを参照してください。

※ MS-DOSやWindows 95/98/Me、また拡張機能を無効にしたプロンプト上では errorlevel は環境変数として使用できないので、素直に If errorlevel を使用する必要があります。この場合、プログラムが返す終了コードをすべて把握して、「~以上」の判定で誤作動を起こさないように注意する必要があります。

サンプル 3 (バッチファイル)

@echo off
setlocal enabledelayedexpansion
set MY_COUNTER=1

:main
bar.exe "%1"
if %errorlevel%==0 (
    echo 正常に終了しました。
    exit /b 0
)
if %MY_COUNTER% lss 3 (
    set /a MY_COUNTER="MY_COUNTER+1"
    echo プログラムはエラーコード %errorlevel% を返しました。リトライします... (!MY_COUNTER!回目の実行をします)
    goto main
)
echo プログラムはエラーコード %errorlevel% を返しました。終了します。
exit /b %errorlevel%

[Windows NT 系] [拡張機能] プログラム bar.exe にバッチファイルの1番目の引数を渡して実行し、その終了コードをチェックしています。もし実行に失敗した場合、「MY_COUNTER」の値が3未満の時はMY_COUNTERの値を1増やし、次が何回目の実行かを表示してもう一度 bar.exe を実行します。もし実行に失敗して「MY_COUNTER」が3になっていたら、プログラムの終了コードをそのままバッチファイルの終了コードとしています。

この例では、Ifで条件に一致したときのコマンドを、「( )」を使って複数行にわたって記述しています。その際、「MY_COUNTER」の値を正しく参照するためにSetlocal「!」文字を使用しています。この例では、「!MY_COUNTER!」を「%MY_COUNTER%」と記述してしまうと、処理がここに来た時に実際に出力したい数値よりも1少ない数値が画面に出力されてしまいます。

関連項目