1

I have a control_script.cmd that works as it is but is a little hard to read. Basically, I want to quit my script when the first program returns an error.

set text=converting something...
call %libdir%\1_convert_xlsx.cmd 
set rvalue=%errorlevel%
call :check_errorlevel !rvalue! "!text!"
if !rvalue! geq 1 goto :my_error_handler

set text=loading something...
call %libdir%\2_load_something.cmd 
set rvalue=%errorlevel%
call :check_errorlevel !rvalue! "!text!"
if !rvalue! geq 1 goto :my_error_handler

:check_errorlevel 
set rvalue=%~1
set text=%~2
echo do something with rvalue and text
exit /b 0

:my_error_handler
exit /b 1

it would be much nicer if I could move the if-clause into the check_errorlevel part, like

call %libdir%\1_convert_xlsx.cmd 
call :check_errorlevel %errorlevel% "converting something..."

call %libdir%\2_load_something.cmd  
call :check_errorlevel %errorlevel% "loading something..."

:check_errorlevel 
set rvalue=%~1
set text=%~2
echo do something with rvalue and text
if !rvalue! geq 1 goto :my_error_handler
exit /b 0


:my_error_handler
exit /b 1

But here I face the issue that :my_error_handler is not defined within :check_errorlevel and I do not see any other way to go directly from :check_errorlevel to the end of my cmd. Is there any?

Best regards, Peter

Peter Frey
  • 361
  • 4
  • 17
  • Is there any reason your not just using `If not errorlevel 0 (command)` as opposed to a resource intensive call function? - Given that your already using delayed expansion, it could easily be scripted as a macro to capture the errorlevel, perform the test and output a string relevant to the command being tested via substring modification. The macro method avoids adding another environment stack to the command processor – T3RR0R Sep 30 '20 at 14:01
  • The reason you cant just exit /b to the end of the script is that when you use call, the called label is executed as an independent child environment that returns control to the parent environment after execution. – T3RR0R Sep 30 '20 at 14:02
  • @T3RR0R: child environment; yes but what's the bypass? reason: actually, check_errorlevel contains a tree of if-else statements. I am just cutting the code short. – Peter Frey Sep 30 '20 at 14:27
  • The bypass is not to use a subroutine that must first return control to the script. You could do a hard `exit`, however I assume that is not desired here. – T3RR0R Sep 30 '20 at 14:33
  • right, maybe I just try your macro style. – Peter Frey Sep 30 '20 at 14:37
  • You'll need `exit /B` before `:check_errorlevel`. Anyway, why not just doing `call "%libdir%\….cmd" || echo Something went wrong.& exit /B`? – aschipfl Oct 01 '20 at 00:27
  • hehe, the reason is that I am not familiar with | :-) on the other side better learn pipe then learn macro I guess... thank you. – Peter Frey Oct 27 '20 at 16:12
  • @aschipfl for a quick check I just found "|" which might work for me. Do you have any link to the usage of "||" for me? Is || something like "execute right statement only if left statement returns an error?! ... whats means that errorlevel is geq 1, right? – Peter Frey Oct 27 '20 at 16:16
  • found it myself... || equals if errorlevel neq 0 – Peter Frey Oct 27 '20 at 17:41
  • Great! Anyway, take a look at [this](https://ss64.com/nt/syntax-redirection.html). By the way, my previous suggestion should have been `call "%libdir%\….cmd" || (echo Something went wrong.& exit /B)`, because without parentheses, `exit /B` will always run… – aschipfl Oct 27 '20 at 18:10
  • For a real STOP in a nested call, try a look at [Exit from nested batch file](https://stackoverflow.com/questions/17655345/exit-from-nested-batch-file) and the another one [Does Windows batch support exception handling?](https://stackoverflow.com/q/31445330/463115) – jeb Nov 03 '20 at 11:32

2 Answers2

1

%So after @aschipfl hint, I am going to go for the code below. I actually still need to test it but I am having a good feeling here.

call %libdir%\1_convert_xlsx.cmd 
call :check_errorlevel %errorlevel% "converting something..." || goto :my_error_handler

call %libdir%\2_load_something.cmd  
call :check_errorlevel %errorlevel% "loading something..." || goto :my_error_handler

goto :all_fine

:check_errorlevel 
set rvalue=%~1
set text=%~2
echo do something with rvalue and text
if %rvalue% GEQ 1 ( set my_errorlevel = 1 ) else ( set my_errorlevel = 0 )
REM notice that this errorlevel only transfers the input-errorlevel and is not an errorlevel by itself.
exit /b %my_errorlevel%

:my_error_handler
exit /b 1

:all_fine
exit /b 0

edit: {} to () thanks to stefano

Peter Frey
  • 361
  • 4
  • 17
  • `if %rvalue% GEQ 1 { set my_errorlevel = 1 } else { set my_errorlevel = 0 }` surely doesn't work. It should be `if %rvalue% GEQ 1 (set my_errorlevel=1) else (set my_errorlevel=0)` – Stephan Nov 03 '20 at 10:58
0

Here is an example of the macro style I mentioned

@Echo off & Setlocal EnableExtensions EnableDelayedExpansion
rem // macro definition within delayed expansion environment requires exclaimation marks to be thrice escaped.
rem // outer For %%n loop uses If ()Else construct to capture the trailing string within the output variable at the time of expansion.
Set "CHKErr=For %%n in (1 2)Do If %%n==2 (If Not "^^^!Errorlevel^^^!"=="0" (Echo/Failed [^^^!Errorlevel^^^!] - ^^^!Output^^^!&Endlocal &Goto :EOF)Else (Echo/Success - ^^^!Output^^^!))Else Set Output="
 Call :truelabel 2> Nul
 %CHKErr%:truelabel
 Call :falselabel 2> Nul
 %CHKErr%:falselabel
 Echo/You'll never see this on fail.
Goto :Eof

:truelabel
Exit /B 0
T3RR0R
  • 2,747
  • 3
  • 10
  • 25