Search code examples
batch-fileerror-handlingbatch-processingerrorlevel

Handling error messages with files run automatically with a batch script


I'm using a batch script to automatically run some simulations and record data. However, because this is for the purposes of testing, I routinely get error messages that pop up from the batch script because there was a bug in the simulation software. I'd like to add in a couple of different things into the script, both of which I'm extremely fuzzy on the implementation, hence my question.

1st, I'd like to put in a script that will cause an entry to become null when an error message pops up.

I have a loop that looks like this

for /f "delims=_" %%J IN ('forfiles /p "%%F" /m *.ext/c "cmd /c echo @path"')  DO (
    set start=!time!
    start "PROGRAM"  /D "c:\Path\to\the\PROGRAM" /Wait program -r  %%J  

    rem This loop uses a regular expression to find the database name from the .ext file
    rem and sets it to a variable.
    for /f "tokens=3 delims=<>" %%a in  ('findstr "<Name>ABCDir" "%%~fJ"') do set name=%%a

set end=!time!

rem The following two loops convert start time and end time to centiseconds.
rem The time variable will be converted to minutes inside a sql query so that floats are possible.
for /F "tokens=1-4 delims=:.," %%a in ("!start!") do (
        set /a "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
    )       

for /F "tokens=1-4 delims=:.," %%a in ("!end!") do (
        set /a "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
    )

rem Calculate the elapsed time by subtracting values
set /A elapsed=end-start

sqlcmd -S SERVER -d DATABASE -v Var1 = "!name!" Var2 = "%variable2%" Var3 = !elapsed! Var4 = %variable4% -i "\\path\to\the\query\Insert.sql"
)

So I'd like so that everytime an error message pops up, the script starts running the next file and changes the !elapsed! variable to null.

But I would like to also add in a script that will echo what the errorlevel is that pops up. I've seen one method of doing this is like this:

@ECHO OFF
IF ERRORLEVEL 1 SET ERRORLEV=1
IF ERRORLEVEL 2 SET ERRORLEV=2
IF ERRORLEVEL 3 SET ERRORLEV=3
IF ERRORLEVEL 4 SET ERRORLEV=4
   •
   •
   •
IF ERRORLEVEL 254 SET ERRORLEV=254
IF ERRORLEVEL 255 SET ERRORLEV=255
ECHO ERRORLEVEL = %ERRORLEV%

but there seems like there should be a more efficient way to do this like with a loop that counts up errorlevel i set errorlev = i where i=0 and goes to n.

I really appreciate any insight you guys can offer.


Solution

  • Firstly, if all you want to do is conditional execution based on the zero or non-zero exit code of "PROGRAM", use && and || to designate code blocks for success or fail like this:

    for /f "delims=_" %%J IN ('forfiles /p "%%F" /m *.ext/c "cmd /c echo @path"')  DO (
        set start=!time!
        start "PROGRAM"  /D "c:\Path\to\the\PROGRAM" /Wait program -r  %%J && (
    
            rem program exited status 0 (success)
    
            rem This loop uses a regular expression to find the database name from the .ext file
            rem and sets it to a variable.
            for /f "tokens=3 delims=<>" %%a in  ('findstr "<Name>ABCDir" "%%~fJ"') do set name=%%a
    
            set end=!time!
    
            rem The following two loops convert start time and end time to centiseconds.
            rem The time variable will be converted to minutes inside a sql query so that floats are possible.
            for /F "tokens=1-4 delims=:.," %%a in ("!start!") do (
                set /a "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
            )       
    
            for /F "tokens=1-4 delims=:.," %%a in ("!end!") do (
                set /a "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
            )
    
            rem Calculate the elapsed time by subtracting values
            set /A elapsed=end-start
    
            sqlcmd -S SERVER -d DATABASE -v Var1 = "!name!" Var2 = "%variable2%" Var3 = !elapsed! Var4 = %variable4% -i "\\path\to\the\query\Insert.sql"
    
        ) || (
    
            rem Program exited status non-zero (fail)
            set "elapsed="
            rem Continue looping to next result of forfiles
    
        )
    )
    

    See this page for more on this sort of conditional execution.

    Regarding echoing the errorlevel, it's already in %ERRORLEVEL%. You don't have to use a series of if ERRORLEVEL statements to set it. Try this on the command-line:

    cmd /c exit /b 5
    echo %ERRORLEVEL%
    

    It should echo 5.

    One other note, although I'm not sure you still need it knowing what you know now, if ERRORLEVEL N checks if %ERRORLEVEL% is greater than or equal to N. So if ERRORLEVEL 5 would return true if %ERRORLEVEL% is 8. For this reason, series of if ERRORLEVEL commands are usually written in descending order.

    if ERRORLEVEL 3 (
        do stuff
    ) else if ERRORLEVEL 2 (
        do something else
    ) else etc...