-1

I have a rather confusing problem when using nested CALL functions and CHOICE commands inside of a batch file.

To summarize in pseudo code:

1.) Use a CHOICE command, which uses CALL :function1 when the correct option is selected

2.) :function1 uses CALL :setVar_n

3.) :setVar_n sets a list of variables, and ends with EXIT /B to return to :function1

4.) :function1 has a CHOICE command (Y/N), where Y will continue to perform operations then end with EXIT /B, and N ends with EXIT /B immediately

The issue:

The CHOICE command in :function1 always evaluates to N (the second option) regardless of input.

I don't understand why using %ERRORLEVEL% fails, while IF ERRORLEVEL works fine. I am also unsure why the use of CALL causes %ERRORLEVEL% to stop working in the first place.

I'm trying to avoid rewriting every choice command (There must be at least 50, some with 25+ options).

When it's written using %ERRORLEVEL% it fails:

::Return from setVar_n here

CHOICE /C YN /M "Continue? Y/N >"
IF %ERRORLEVEL%==2 (EXIT /B)

::function1 continues here

If I use IF ERRORLEVEL:

::Return from setVar_n here

CHOICE /C YN /M "Continue? Y/N >"
IF ERRORLEVEL 2 (EXIT /B)

::function1 continues here

It works properly. The issue is that the CHOICE problem persists even after :function1 ends. It affects all CHOICE commands in the entire file, so %ERRORLEVEL% cannot be used at all.

Can anyone shed some light on this issue?

Here's a full file code to test with, which might make more sense:

@ECHO OFF

:start
choice /c ABC
if %errorlevel%==1 (goto start)
if %errorlevel%==2 (call :function1)
if %errorlevel%==3 (goto start)

echo Function 1 completed
pause
choice /c ABC
if %errorlevel%==1 (echo 1)
if %errorlevel%==2 (echo 2)
if %errorlevel%==3 (echo 3)
pause
exit


:setVar
set /a var1=2
set /a var2=3
exit /b

:function1
echo In Function 1
call :setVar
choice /c YN /m "Continue (Y) or Finish (N)"
if %errorlevel%==2 (exit /b)
echo Still inside function 1
exit /b

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
  • Your issue is unclear, as you have shown insufficient code for us to put it into context. However my advice is that you use `If ErrorLevel 2` instead of `If %ERRORLEVEL%==2`. – Compo Oct 21 '19 at 18:15
  • The only reason, I can imagine (with the code shown above) is that `%errorlevel%` is explicitly set to some value, overwriting and so disabling the system variable. Do a `set "errorlevel="` and try again. – Stephan Oct 21 '19 at 18:27
  • That would work, but I'm trying to avoid rewriting all of the instances of CHOICE. I'm also trying to understand why using CALL twice causes %errorlevel% to be unusable. – RCAProduction Oct 21 '19 at 18:27
  • Stephan, I can give that a shot, but I think it had the same issue, as in, %errorlevel% fails to be set by CHOICE. – RCAProduction Oct 21 '19 at 18:28
  • I never heard `choice` to be unreliable. The only other option would be a [delayed expansion](https://stackoverflow.com/questions/30282784/variables-are-not-behaving-as-expected/30284028#30284028) problem, but that doesn't apply to the code you are showing. – Stephan Oct 21 '19 at 18:32
  • One should recall here that `if %ERRORLEVEL%== ...` and `IF ERRORLEVEL ...` are _not_ equivalent; the latter test succeeds if the "errorlevel" is _equal to or greater than_ the specified value, whereas the former tests for an exact string match. Thus, if using `IF ERRORLEVEL`, one should test for the possible values in descending order. Note that if a numeric comparison is desired with `IF %ERRORLEVEL% ...`, one should use `EQU` (equal), `NEQ` (not equal), `LSS` ([strictly] less than), `LEQ` (less than or equal to), etc. See [SS64 on `IF`](https://ss64.com/nt/if.html). – Jeff Zeitlin Oct 21 '19 at 18:37
  • Jeff Zeitlin, I was aware of the descending order requirement, although I had not considered using EQU for these before. Is it possible to have %errorlevel% be true using EQU but false using == ? – RCAProduction Oct 21 '19 at 18:46
  • I did a little testing. In the example file, everything works fine. However, in the real file, the issue persists. Using EQU instead of == does not change the result. – RCAProduction Oct 21 '19 at 21:00

1 Answers1

0

Thanks to Stephan for the correct answer in the comments.

The solution is to use

set "errorlevel="

Before the choice command.

  • 1
    the solution isn't "to use `set "errorlevel="` *before the `choice` command* ", but to *never ever* assign a value to `%errorlevel%`, as this disables the proper function of the systemvariable. – Stephan Oct 22 '19 at 07:49
  • @Stephan - Agreed that one should never set a user defined ERRORLEVEL variable. But one doesn't always have control of the incoming environment. So using `set "errorlevel="` at the top of a critical batch script is an appropriate prophylactic measure. I've never needed to do it, but it can't hurt. – dbenham Oct 22 '19 at 16:21