0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

batで外部batファイルの存在を確認してから実行し、返り値で処理を変えたい!if文内で外部ファイルcallしてerrorlevelを取得して楽勝かと思ってた

0
Posted at

はじめに

楽勝かと思ってたら、プログラミング言語が変わるとはまって時間がかかったりしたことないですか?
私も普段はwindowsバッチファイルを作成していないので、「外部ファイルbatの存在を確認してから実行し、返り値で処理を変える」だけなんて楽勝!かと思ってたら、ERRORLEVEL変数が思った値で返ってこないことにはまって1時間失ったので記事にしました。

結論

if文にexit関数を用いて実行外部ファイルの存在を確認し、call関数を使って外部ファイルを呼び出す。
呼び出された外部ファイルの最後では exit /B 1 などで返り値(今回の場合は1)を返す。
呼び出し元ファイルでは変数ERRORLEVELに外部ファイルの返り値が入るが、if文内で変数ERRORLEVELを使う場合は 遅延環境変数の展開 を使う。
(遅延環境変数の展開を使う際には、setlocal enabledelayedexpansion を忘れない。)

call.bat
@echo off
setlocal enabledelayedexpansion
set FILE=C:¥temp¥test.bat
if exist "%FILE%" (
    call %FILE%
    rem 遅延環境変数の展開のために、変数ERRIRLEVELを%ではなく!で囲む
    if !ERRORLEVEL! == 1 (
        echo 返り値は1です。
        pause
    ) else (
        echo 返り値は1ではありません。
        pause
    )
)
endlocal
test.bat
@echo off
echo hello
pause
exit /b 1

解説

外部batファイルからの返り値の受け取り

外部batファイルを呼び出すには、call関数を使います。
呼び出された外部batファイル内で exit /b を使用することで、環境変数ERRORLEVELに値を入れることができます。
呼び出し元ファイルでは環境変数ERRORLEVELを使用することで、処理を分けることができます。

call.bat
@echo off
set FILE=C:¥temp¥test.bat
call %FILE%
if %ERRORLEVEL% == 1 (
    echo 返り値は1です。
    pause
) else (
    echo 返り値は1ではありません。
    pause
)
rem 出力結果は「返り値は1です。」
test.bat
@echo off
echo hello
pause
exit /b 1
rem 出力結果は「hello」

あとは外部ファイルの存在をexit関数で確認するif文を呼び出し元のファイルに加えれば完成!かと思いきや、ここでハマりました。

call.bat
@echo off
set FILE=C:¥temp¥test.bat
if exist "%FILE%" (
    call %FILE%
    if ERRORLEVEL == 1 (
        echo 返り値は1です。
        pause
    ) else (
        echo 返り値は1ではありません。
        pause
    )
)
rem 出力結果は「返り値は1ではありません。」 

出力結果は「返り値は1ではありません。」
何回やっても変数ERRORLEVELが1になりません。びっくりしました。
実はbatファイルは環境変数の即時展開がされています。

if文中における変数

batにおいて、変数はif文やfor文の中でなければ思った通りに値が置き換わります。

ex1.bat
set HOGE="ほげ"
set HOGE="ふが"
echo %HOGE%
pause
rem 出力結果は「ふが」

しかし、if文やfor文の中で変数を置き換えた場合、 その行を読み込んだ時に変数の置き換えが発生 するので、変数は値が置き換え前の値になります。

ex1.bat
set HOGE="ほげ"
if %HOGE%=="ほげ" (
    set HOGE="ふが"
    echo %HOGE%
    pause
)
rem 出力結果は「ほげ」

つまり

if %HOGE%=="ほげ" (
    set HOGE="ふが"
    echo %HOGE%
    pause
)

の部分は一気に読み込まれ、

if %HOGE%=="ほげ"

と

(
    set HOGE="ふが"
    echo %HOGE%
    pause
)

の部分は同じタイミングで読み込まれます。
これを環境変数の即時展開というそうです。

なので、if文条件式とは別に実際に実行する際に変数の読み込みたい場合は 遅延環境変数の展開 を使用します。
遅延環境変数の展開を使用するには、setlocal enabledelayedexpansion と endlocal で囲い、%ではなく!で変数を読み込みます。

ex1.bat
setlocal enabledelayedexpansion
set HOGE="ほげ"
if !HOGE!=="ほげ" (
    set HOGE="ふが"
    echo %HOGE%
    pause
)
endlocal
rem 出力結果は「ふが」

私の呼び出し元のファイルも 遅延環境変数の展開 を導入すると以下の通りになります。

call.bat
@echo off
set FILE=C:¥temp¥test.bat
call %FILE%
if %ERRORLEVEL% == 1 (
    echo 返り値は1です。
    pause
) else (
    echo 返り値は1ではありません。
    pause
)
rem 出力結果は「返り値は1です。」

おわりに

batで外部batファイルを存在確認して呼び出して、返り値で処理を変える方法についてまとめました。
遅延環境変数の展開 について一度知れば、次に同じ目に遭っても早く問題から脱出できそうです。
いつもと異なるプログラミング言語を使うのも勉強になりますね。

参考記事

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?