1
0

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 3 years have passed since last update.

バッチファイルのforループ内でのERRORLEVEL処理

Last updated at Posted at 2021-08-12

目次

  1. 結論
  2. forループでの挙動
  3. 参考文献

結論

正常終了以外を検知したい場合、for文の中では、

if ERRORLEVEL 1 (
    処理
)

を使いましょう。

forループでの挙動

簡単に言うと、forループ内の命令で正常終了しなかった場合でも、%ERRORLEVEL%の値が変わるのはループを抜けた後なので、for文内で%ERRORLEVEL%との大小比較では、欲しい挙動を示してくれないということです。

実際に挙動を比較してみましょう。2通りのバッチファイルを用意します。

1つ目は、for文の中で %ERRORLEVEL% と数値を比較することによって、正常終了しているかどうかを判別するバッチファイルです。

test1.bat
@echo off

rem 正常終了する命令で ERRORLEVEL を 0 に
python --version
echo before loop ERRORLEVEL: %ERRORLEVEL%
for %%i in (*.py) do (
    python %%i
    echo   %%i ERRORLEVEL: %ERRORLEVEL%
    if %ERRORLEVEL% neq 0 (
        exit /b
    )
)
echo  after loop ERRORLEVEL: %ERRORLEVEL%
echo finish

2つ目は、for文の中で if文の ERRORLEVEL を用いた特殊(?)な文法を用いることによって、正常終了しているかどうかを判別するバッチファイルです

test2.bat
@echo off

rem 正常終了する命令で ERRORLEVEL を 0 に
python --version
echo before loop ERRORLEVEL: %ERRORLEVEL%
for %%i in (*.py) do (
    python %%i
    echo   %%i ERRORLEVEL: %ERRORLEVEL%
    if ERRORLEVEL 1 (
        exit /b
    )
)
echo  after loop ERRORLEVEL: %ERRORLEVEL%
echo finish

また、終了ステータス1を返してくれる以下のようなPythonファイルを複数用意します。

error1~9.py
import sys

sys.exit(1)

試してみるディレクトリの中身は、以下のようになります。

test
  ├─── error1.py
  ├─── error2.py
  ├─── error3.py
  ├─── error4.py
  ├─── error5.py
  ├─── error6.py
  ├─── error7.py
  ├─── error8.py
  ├─── error9.py
  ├─── test1.bat
  ├─── test2.bat
  └─── (test3.bat)

準備が整ったところで、早速ですが実行してみましょう。

1つ目のバッチファイルについて、実行結果は以下の通りになりました。

test>test1.bat
Python 3.9.5
before loop ERRORLEVEL: 0
  error1.py ERRORLEVEL: 0
  error2.py ERRORLEVEL: 0
  error3.py ERRORLEVEL: 0
  error4.py ERRORLEVEL: 0
  error5.py ERRORLEVEL: 0
  error6.py ERRORLEVEL: 0
  error7.py ERRORLEVEL: 0
  error8.py ERRORLEVEL: 0
  error9.py ERRORLEVEL: 0
 after loop ERRORLEVEL: 1
finish

pythonプログラムを実行した結果、終了コード1が返されており、%ERRORLEVEL% も1となってループを抜けてほしいのですが、最後まで走り切ってしまっている様子が見て取れます。また、for文から出ると、%ERRORLEVEL% が1となっていることが分かります。

次に、2つ目のバッチファイルについて、実行結果は以下の通りになりました。

test>test2.bat
Python 3.9.5
before loop ERRORLEVEL: 0
  error1.py ERRORLEVEL: 0

for文中で %ERRORLEVEL% を表示させても 0 のままとなってしまっていますが、ERRORLEVEL を用いた分岐処理自体はうまくいっていることが分かります。

さらに、次のようなバッチファイルを実行してみましょう。

test3.bat
@echo off

rem ERRORLEVEL を 1 に
python error1.py
echo before loop ERRORLEVEL: %ERRORLEVEL%
for /l %%i in (1, 1, 9) do (
    python --version
    echo     count %%i ERRORLEVEL: %ERRORLEVEL%
    if ERRORLEVEL 1 (
        exit /b
    )
)
echo  after loop ERRORLEVEL: %ERRORLEVEL%
echo finish

これを実行すると、次のような実行結果が得られます。

test>test3.bat
before loop ERRORLEVEL: 1
Python 3.9.5
    count 1 ERRORLEVEL: 1
Python 3.9.5
    count 2 ERRORLEVEL: 1
Python 3.9.5
    count 3 ERRORLEVEL: 1
Python 3.9.5
    count 4 ERRORLEVEL: 1
Python 3.9.5
    count 5 ERRORLEVEL: 1
Python 3.9.5
    count 6 ERRORLEVEL: 1
Python 3.9.5
    count 7 ERRORLEVEL: 1
Python 3.9.5
    count 8 ERRORLEVEL: 1
Python 3.9.5
    count 9 ERRORLEVEL: 1
 after loop ERRORLEVEL: 0
finish

forループ中では正常終了する命令を実行した場合でも、forループに入る直前で正常終了しない命令を実行してしまうと、こちらも正しくない結果が得られてしまうことも分かります。

以上のように、forループ中での %ERRORLEVEL% の値は、forループに入る直前の %ERRORLEVEL% の値で固定されてしまうので、分岐処理を書く際には気を付けましょう。

参考文献

  1. 環境変数展開のタイミング(バッチ)
  2. errorlevel(終了コードを取得する)
  3. batコマンドでPythonスクリプトの戻り値を取る際の注意点
  4. .bat(バッチファイル)のifコマンド解説。
  5. 返り値をバッチファイルで受け取るときの注意点
1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?