web-dev-qa-db-ja.com

DOSBoxで `%errorlevel%`が空の文字列に展開されるのはなぜですか?

古いプログラムのDOSBoxスクリプトを自動化しようとして、通常はerrorlevelにある終了コードを使用してプログラムフローを制御したいと思いました。

入力はhello_db.batファイルで与えられます:

@echo off
set msg=Hello
echo %msg%
dir
echo errorlevel = %errorlevel%

次に、DOSBoxがdosbox hello_db.batで呼び出されます。

出力は次のとおりです。

Hello
{Listing from dir}
errorlevel = 

したがって、%errorlevel%dirコマンドの終了コードではなく、空の文字列に展開されましたが、最初のmsg変数は正しく展開できました。

DOSBoxにスクリプトでerrorlevelを正しく展開させるにはどうすればよいですか?

@ phuclvによる回答に基づく短い回答:

要件は、OKでない場合(エラーレベル!= 0)にコマンドの後に一時停止を挿入することであったため、次のようになりました。

set errorany=0
:: Command is inserted here...
if errorlevel 1 set errorany=1

:: Make pause if not OK
if %errorany%==1 pause
1
Morten Zilmer

%ERRORLEVEL%はMS-DOSの変数ではないためです。これはDR-DOSおよびcmd固有です。 それらは非常に異なるものです

%ERRORLEVEL%

DR-DOS 7.02以降のCOMMAND.COMでは、この疑似変数は、外部プログラムまたはRETURNコマンドによって返された最後のエラーレベルを返します。 「0」..「255」。 Windowsでの同じ名前の疑似変数%ERRORLEVEL%およびIF ERRORLEVEL条件付きコマンドも参照してください。

https://en.wikipedia.org/wiki/Environment_variable#DOS

%DATE%または他の多くの変数と同様に、これらはcmd.exeの新機能であり、 コマンド拡張 を有効にする必要があります

コマンド拡張機能が無効になっている場合、次の動的変数にはアクセスできません。

%CD% %DATE% %TIME% %RANDOM% %ERRORLEVEL% %CMDEXTVERSION% %CMDCMDLINE% %HIGHESTNUMANODENUMBER%

https://ss64.com/nt/syntax-variables.html

DOS互換性のためにコマンド拡張をオフにすると、Windowscmd.exeでこれらの変数にアクセスできなくなります。


MS-DOSとそのcommand.comに固執する必要がある場合、エラーレベルを取得する唯一の方法は、降順で if errorlevel を使用することです。

...
if errorlevel 4 set errorlvl=4
if errorlevel 3 set errorlvl=3
if errorlevel 2 set errorlvl=2
if errorlevel 1 set errorlvl=1

幸い、255個のエラーコードすべてを実際に処理する必要がある場合は、実際に255行のコードを記述する必要はありません。しかし、それはまだかなり長いので、[を参照してください。§]興味のある方は以下

代替シェルをインストールできる場合(config.sysでShell=\path\to\Shell.comを設定することにより)、いくつかの3つがありますrd エラーレベル変数を持つパーティシェル。たとえば 有名な4DOSには%_?があります

ほとんどの内部4DOSコマンドは、エラーレベル値を設定します。 4DOSには、外部プログラム終了コード(%?)、外部プログラム終了の理由(%??)、終了コードの最後の内部コマンド(%_?)、および最後のDOSエラー(%_SYSERR)の内部変数があります。 4DOSは、別の値と等しい、より小さい、以下、より大きい、より大きい、または等しくない値を判別できるため、特定のエラーを簡単にキャッチできます。

IF "%_?" NE "" GOSUB ERR_HANDLER
:ERR_HANDLER
IF %_? == 1 ...
IF %_? == 2 ...
...
RETURN

ON ERROR...コマンドは、エラーをキャッチ(および回復)するためにも使用できます。


§ 考えられるすべてのエラーレベルを確認する方法:

@ECHO OFF
REM Reset variables
FOR %%A IN (1 10 100) DO SET ERR%%A=

REM Check error level hundredfolds
FOR %%A IN (0 1 2) DO IF ERRORLEVEL %%A00 SET ERR100=%%A
IF %ERR100%==2 GOTO 200
IF %ERR100%==0 IF NOT "%1"=="/0" SET ERR100=

REM Check error level tenfolds
FOR %%A IN (0 1 2 3 4 5 6 7 8 9) DO IF ERRORLEVEL %ERR100%%%A0 SET ERR10=%%A
IF "%ERR100%"=="" IF %ERR10%==0 SET ERR10=

:1
REM Check error level units
FOR %%A IN (0 1 2 3 4 5) DO IF ERRORLEVEL %ERR100%%ERR10%%%A SET ERR1=%%A
REM Modification necessary for errorlevels 250+
IF NOT ERRORLEVEL 250 FOR %%A IN (6 7 8 9) DO IF ERRORLEVEL %ERR100%%ERR10%%%A SET ERR1=%%A
GOTO End

:200
REM In case of error levels over 200 both
REM tenfolds and units are limited to 5
REM since the highest DOS error level is 255
FOR %%A IN (0 1 2 3 4 5) DO IF ERRORLEVEL 2%%A0 SET ERR10=%%A
IF ERR10==5 FOR %%A IN (0 1 2 3 4 5) DO IF ERRORLEVEL 25%%A SET ERR1=%%A
IF NOT ERR10==5 GOTO 1

:End
REM Clean up the mess and show results
SET ERRORLEV=%ERR100%%ERR10%%ERR1%
FOR %%A IN (1 10 100) DO SET ERR%%A=
ECHO ERRORLEVEL  %ERRORLEV%

クレジット: https://www.robvanderwoude.com/errorlevel.php

2
phuclv

@phuclvが述べているように、%ERRORLEVEL%はDOSよりも新しいため、使用しないでください。代わりに、エラーレベルがn以上であるかどうかをテストする古いIF ERRORLEVEL n構造を使用してください。これは、考えられるエラーレベルを降順の順序でテストする必要があることを意味します。

IF ERRORLEVEL 5 ...  
IF ERRORLEVEL 4 ...  
IF ERRORLEVEL 3 ...
...

SS64でのエラーレベル でのエラーレベルの検出に関するセクションを読み、DOSとの互換性について説明している最初の部分に特に注意を払う必要があります。

1
Jeff Zeitlin