2

Trying to automate some DOSBox scripting for an old program, I wanted to use the exit code usually in errorlevel to control the program flow.

The input is given in a hello_db.bat file:

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

Then DOSBox is called with dosbox hello_db.bat.

The output is:

Hello
{Listing from dir}
errorlevel = 

So the %errorlevel% expanded to an empty string instead of the exit code from the dir command, where as the first msg variable could expand correctly.

How can I make DOSBox expand the errorlevel correctly in the script?

Short answer based on through answer by @phuclv:

The requirement was to insert a pause after the command if not OK (errorlevel != 0), so ended up doing:

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

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

phuclv
  • 30,396
  • 15
  • 136
  • 260
Morten Zilmer
  • 650
  • 1
  • 5
  • 14

2 Answers2

3

Because %ERRORLEVEL% is not a variable in MS-DOS. It's DR-DOS and cmd-specific. They're very different things

%ERRORLEVEL%

In COMMAND.COM of DR-DOS 7.02 and higher, this pseudo-variable returns the last error level returned by an external program or the RETURN command, f.e. "0".."255". See also the identically named pseudo-variable %ERRORLEVEL% under Windows and the IF ERRORLEVEL conditional command.

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

Like %DATE% or many other variables, they're new features of cmd.exe and require command extension to be enabled

If Command Extensions are disabled, the following dynamic variables will be not accessible:

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

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

If you turn off command extension for DOS compatibility you'll lose access to those variables on Windows cmd.exe


If you have to stick with MS-DOS and its command.com then the only way to get errorlevel is to use if errorlevel in descending order

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

Fortunately if you really have to deal with all 255 error codes then you don't actually have to write 255 lines of code. But it's still rather long so see [§] below if you're interested

If you can install alternative shells (by setting SHELL=\path\to\shell.com in config.sys) then there are some 3rd party shells with an errorlevel variable. For example the famous 4DOS has %_?

Most internal 4DOS commands set errorlevel values. 4DOS has internal variables for external program exit code (%?), reason for external program termination (%??), exit code last internal command (%_?) and last DOS error (%_SYSERR). Since 4DOS is able to determine values equal, less than, less or equal, greater, greater or equal, unequal to another value, it's easy to catch specific errors:

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

The ON ERROR... command is also available to catch (and recover from) errors.


§ How to check for every possible errorlevel:

@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%

Credit: https://www.robvanderwoude.com/errorlevel.php

phuclv
  • 30,396
  • 15
  • 136
  • 260
1

You should not attempt to use %ERRORLEVEL%, as that is more recent than DOS, as @phuclv states. Instead, use the older IF ERRORLEVEL n construct, which tests for whether the error level is n or greater. This means that you should test possible error levels in descending order:

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

You should read the section on Detecting Errorlevel at Errorlevel at SS64, paying specific attention to the beginning where it discusses compatibility with DOS.

Jeff Zeitlin
  • 5,136