laggingreflex
laggingreflex

Reputation: 34627

Why does Choice not work inside For loop

FOR /L %%i IN (1,1,100) DO (
    choice
    echo %ErrorLevel%
    )

%ErrorLevel% is always 0 no matter what choice you enter.

Upvotes: 3

Views: 722

Answers (1)

James K
James K

Reputation: 4055

You are checking the errorlevel the wrong way.

Variables and commands inside a bracket pair like this...

(
  command1
  command2
  command3
)

...act like they were run on a single line, like this command1 & command2 & command3.

Try this at the command line.

choice & echo %errorlevel%

If you execute the above command more than once, you will see that the previous errorlevel is echoed, not the current one.

Or try this on the command line:

set x=yes
( echo %x%
  set x=no
  echo %x%
)

Your output will be:

yes
yes

Just as if you'd entered echo %x% & set x=no& echo %x%

I like to think of it as the system doesn't have the time to update the variables. (Though it's more accurate to say that the variables only get updated after the entire line is executed.) This is true with all variables, not just the errorlevel.

To make variables in for loops work normally you need to call an internal label in your batch file (or an external batch file) like this.

@echo off
  FOR /L %%i IN (1,1,100) DO call :dostuff %%i
goto :eof

:dostuff
  choice /m "Question #%1"
  echo %ErrorLevel%

==================================== Solution To Question Below

Alternatively, Microsoft has created a method for accessing the current value of variables inside of a bracket pair, they call it 'Delayed Expansion' because the line of code is interpreted twice.

To activate this mode you use the setlocal command with the enableDelayedExpansion switch, and access the variables with the ! character like this. FYI endlocal turns off the effects.

@echo off
setlocal enableDelayedExpansion
for /L %%i in (1,1,100) do (
  choice /m "Question #%%i"
  echo !ErrorLevel!
)
endlocal

As you can see my first example is easier to code, but my second example is easier to read. Whichever method you use will depend upon your needs and re-usability.

The setlocal command also has the effect of creating temporary variables that die after the endlocal command. This means you don't need to delete them when your batch file ends, and reverts any variables you changed during execution back to their original values. This is nice because you don't have to worry about 'stepping on' any preexisting variables.

Upvotes: 7

Related Questions