コマンドの終了ステータスが取れない

errorlevel

コマンドプロンプトからコマンドを実行すると、成功したか失敗したかが数値で返ってくる。

その値は errorlevel で見ることができる。

C:\> dir
    ...
C:\> echo %errorlevel%
0

C:\> dirr
'dirr' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

C:\> echo %errorlevel%
9009

C:\>dir not.found
ファイルが見つかりません

C:\> echo %errorlevel%
1

errorlevel に代入してはいけない

この errorlevel は変数ではない。
間違って errorlevel に値を代入してしまうと、コマンド終了ステータスを見ることができなくなる。

C:\> set errorlevel=0

C:\> echo %errorlevel%
0

C:\> dirr
'dirr' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

C:\> echo %errorlevel%
0

errorlevel に値を代入すると、変数の errorlevel ができてしまって、本来の errorlevel にアクセスできないらしい。

errorlevel はエラーの重要度

DOS 用のコマンドを作るとき、

  • ファイルがないときは exit(2)
  • アクセス権がなければ exit(5)
  • etc.

などと設計するのは間違い。

コマンドの終了ステータスはエラーの種類ではなく、エラーの重要度。

C:\> dirr
'dirr' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

C:\> if errorlevel 3 echo NG
NG

C:\> dir not.found
ファイルが見つかりません

C:\> if errorlevel 3 echo NG

if errorlevel を使うと、指定した重要度以上のエラーを検知することができる。
if %errorlevel% == 3 とは違う。

if errorlevel は変数の errorlevel は見ないので、間違って値を代入しても正しく動く。

errorlevel が変化しない

ここからが本題。

コマンドを実行しても errorlevel が変化しなくてハマった。

VisualStudio のデバッグウィンドウには
「プログラム '……' はコード 100 (0x64) で終了しました。」
と表示されているのに、コマンドプロンプトから実行すると errorlevel が 0 のまま。

Cygwinbash から実行しても $? は 100 になるのに。なぜ?

ググッてググッてググりまくった結果、

コマンドプロンプトから実行してもセットされないのに、バッチファイルから実行したらセットされる。

と怒ってる人がいた。

まさかと思ってやってみた。

C:\> type wrap.bat
@echo off

%*
echo %errorlevel%

C:\> wrap foo.exe
100

できた。なぜ??

原因は分からないが、そういうもんらしい。

わざわざバッチファイルを作らなくても、これでイケるみたい。

C:\> cmd /C foo

C:\> echo %errorlevel%
100