38} How can I set and test the errorlevel within a script file?
Many programs return an errorlevel, which then can be tested for. One
of such programs is the familiar C:\WINDOWS\system32\find.exe. For
example one could have
@echo off & setlocal enableextensions
set var_=Testing
echo %var_%|find "a">nul
set el_=%ERRORLEVEL%
echo el_=%el_%
endlocal & goto :EOF
The output would be
C:\_D\TEST>cmdfaq
el_=1
For one of the applications see
Item #42.
EXIT can be used to set the errorlevel. Note the
^2 to avoid it from
being mistaken for a handle.
@echo off & setlocal enableextensions
echo.@exit
/B ^2>tmp$$$.cmd
call tmp$$$
for %%e in (0 1 2 3 4 5 6 7 8 9) do (
if %errorlevel% EQU %%e echo The errorlevel is %%e)
echo Bye from %0 on %date% at %time%
for %%f in (tmp$$$.cmd) do if exist %%f del %%f
goto :EOF
The output will be something like
D:\TEST>cmdfaq
The errorlevel is 2
By from cmdfaq on 19.12.2003 at 8:18:03.21
Another alternative is to utilise
gawk:
@echo off & setlocal enableextensions
:: Requires G(nu)AWK
gawk 'BEGIN{exit 2}'
for %%e in (0 1 2 3 4 5 6 7 8 9) do (
if %errorlevel% EQU %%e echo The errorlevel is %%e)
echo Bye from %0 on %date% at %time%
goto :EOF
The output will be something like
F:\CMD>d:\test\cmdfaq
The errorlevel is 2
By from d:\test\cmdfaq on 19.12.2003 at 8:19:08.69
A wider scale for testing the errorlevel. Note that the errorlevel
must be stored before the next SET because also SET sets the
errorlevel.
@echo off & setlocal enableextensions enabledelayedexpansion
echo.@exit /B ^5>"%temp%\tmp$$$.cmd"
call "%temp%\tmp$$$"
set errorlev_=%errorlevel%
set /a e_=0
:_loop
if !errorlev_! EQU %e_% (
echo The errorlevel is %e_%
) else (
set /a e_+=1
if %e_% LEQ 255 goto _loop)
for %%f in ("%temp%\tmp$$$.cmd") do if exist %%f del %%f
goto :EOF
With Visual Basic Script one can have
@echo off & setlocal enableextensions
:: Make a temporary folder
if not exist c:\mytemp\ mkdir c:\mytemp
::
:: Set the errorlevel
echo WScript.Quit ^5>c:\mytemp\tmp$$$.vbs
cscript //nologo c:\mytemp\tmp$$$.vbs
::
for %%e in (0 1 2 3 4 5 6 7 8 9) do (
if %errorlevel% EQU %%e echo The errorlevel is %%e)
::
:: Clean up
for %%f in (c:\mytemp\tmp$$$.vbs) do del %%f
rmdir c:\mytemp
endlocal & goto :EOF
The output will be
D:\TEST>cmdfaq
The errorlevel is 5
Or, written alternatively
@echo off & setlocal enableextensions
::
:: Build a Visual Basic Script
set skip=
set vbs_=%temp%\slice.vbs
findstr "'%skip%VBS" "%~f0" > "%vbs_%"
::
:: A call returning an errorlevel
cscript //nologo "%vbs_%"
::
for %%e in (0 1 2 3 4 5 6 7 8 9) do (
if %errorlevel% EQU %%e echo The errorlevel is %%e)
::
:: Clean up
for %%f in ("%vbs_%") do if exist %%f del %%f
endlocal & goto :EOF
'
'.......................................................
'A Visual Basic Script returning an errorlevel
WScript.Quit 5 'VBS
Actually, an XP srcipt can return an errorlevel without any
additional tricks as demonstrated below
@echo off & setlocal enableextensions
set cmdfile_="temp $$$.cmd"
echo @exit /b ^2>%cmdfile_%
call %cmdfile_%
for %%e in (0 1 2 3 4 5 6 7 8 9) do (
if %errorlevel% EQU %%e echo The errorlevel is %%e)
for %%f in (%cmdfile_%) do if exist %%f del %%f
endlocal & goto :EOF
The output will be
D:\TEST>cmdfaq
The errorlevel is 2
Is there any reason why echo The errorlevel is %errorlevel% wouldn't
accomplish the same, even showing errorlevels above 9?
Of course, if the echoing is all that is wished for. But that is not
the essence here. The point is that one may wish to cover a certain
range or levels, and one may wish to take action depending one the
level. That is why the more involved formulation. But, indeed one can
simply write
whateverCommand
echo %%errorlevel%%=%errorlevel%
One important consideration in testing an
errorlevel is to do it immediately after a command, that is without
any other intervening commands that might affect the errorlevel
results.
Furthermore, there are some common mistakes that are made with the
errorlevels. From the days of MS-DOS the following, now optional
format is familiar to some of the readers
if ERRORLEVEL number DoWhatever
The above specifies a true condition only if the previous program run
by CMD.EXE returned an exit code equal to
or
greater than number. That is easily misunderstood or forgotten.
For example, consider
@echo off & setlocal enableextensions
dir /a:d C:\|findstr /c:"No such folder"
echo %%errorlevel%%=%errorlevel%
if errorlevel 0 echo The errorlevel is 0
endlocal & goto :EOF
The output will be
C:\_D\TEST>cmdfaq
%errorlevel%=1
The errorlevel is 0
That happens because
ERRORLEVEL 0
always is true.
In the XP scripting it is more clear to write
@echo off & setlocal enableextensions
dir /a:d C:\|findstr /c:"No such folder"
echo %%errorlevel%%=%errorlevel%
if
%errorlevel% EQU 0 echo The errorlevel is 0
endlocal & goto :EOF
The output will be
C:\_D\TEST>cmdfaq
%errorlevel%=1
Another potential source of confusion is setting the errorlevel
directly with set. It is not advisable to do that. For example
@echo off & setlocal enableextensions
set errorlevel=0
dir /a:d C:\|findstr /c:"No such folder"
echo %%errorlevel%%=%errorlevel%
endlocal & goto :EOF
The output will be
C:\_D\TEST>cmdfaq
%errorlevel%=0 (when it is rather expected to be 1)
Yet another common mistake involves misunderstading
or ignoring delayed variable expansion (the principle is not limited
to errorlevels, but is typical in
for
and
if constructs). Consider
@echo off
setlocal enableextensions
enabledelayedexpansion
set cmdfile_=%temp%\tmpcmd.cmd
echo @exit /b ^2>"%cmdfile_%"
if "%OS%"=="Windows_NT" (
call "%cmdfile_%"
echo errorlevel=%errorlevel%)
if "%OS%"=="Windows_NT" (
call "%cmdfile_%"
echo errorlevel=!errorlevel!)
for %%f in ("%cmdfile_%") do if exist %%f del %%f
endlocal & goto :EOF
The output will be
C:\_D\TEST>cmdfaq
errorlevel=0
errorlevel=2
Where only the latter is correct.
If for some reason you wish to use the old DOS errorlevel cumbersome
errorlevel testing syntax, the following demonstration might be of
help.
@echo off & setlocal enableextensions
set cmdfile_=%temp%\tmpcmd.cmd
::
echo @exit /b ^2>"%cmdfile_%"
::
echo.
call "%cmdfile_%"
if errorlevel 3 if not errorlevel 4 echo The errorlevel is exactly 3
if errorlevel 2 if not errorlevel 3 echo The errorlevel is exactly 2
if errorlevel 1 if not errorlevel 2 echo The errorlevel is exactly 1
if errorlevel 0 if not errorlevel 1 echo The errorlevel is exactly 0
echo.
::
call "%cmdfile_%"
if errorlevel 3 echo The errorlevel is at least 3
if errorlevel 2 echo The errorlevel is at least 2
if errorlevel 1 echo The errorlevel is at least 1
if errorlevel 0 echo The errorlevel is at least 0
::
for %%f in ("%cmdfile_%") do if exist %%f del %%f
endlocal & goto :EOF
The output will be
C:\_D\TEST>cmdfaq
The errorlevel is exactly 2
The errorlevel is at least 2
The errorlevel is at least 1
The errorlevel is at least 0