为什么选择不在For循环中工作

lag*_*lex 3 batch-file

FOR /L %%i IN (1,1,100) DO (
    choice
    echo %ErrorLevel%
    )
Run Code Online (Sandbox Code Playgroud)

%ErrorLevel%总是0无论你输入什么选择.

Jam*_*s K 7

您正在以错误的方式检查错误级别.

像这样的括号对内的变量和命令......

(
  command1
  command2
  command3
)
Run Code Online (Sandbox Code Playgroud)

......就像他们在一条线上运行一样,就像这样command1 & command2 & command3.

在命令行尝试此操作.

choice & echo %errorlevel%
Run Code Online (Sandbox Code Playgroud)

如果多次执行上述命令,您将看到前一个错误级别被回显,而不是当前错误级别.

或者在命令行上尝试:

set x=yes
( echo %x%
  set x=no
  echo %x%
)
Run Code Online (Sandbox Code Playgroud)

你的输出将是:

yes
yes
Run Code Online (Sandbox Code Playgroud)

就像你进入了一样 echo %x% & set x=no& echo %x%

我喜欢这样想,因为系统没有时间更新变量.(虽然更准确地说变量只在整行执行后才更新.)所有变量都是如此,而不仅仅是错误级别.

要使for循环中的变量正常工作,您需要call在批处理文件(或外部批处理文件)中使用内部标签.

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

:dostuff
  choice /m "Question #%1"
  echo %ErrorLevel%
Run Code Online (Sandbox Code Playgroud)

==================================== 解决问题如下

或者,Microsoft创建了一种方法来访问括号对内部变量的当前值,他们将其称为"延迟扩展",因为代码行被解释了两次.

要激活此模式,请使用setlocalenableDelayedExpansion开关的命令,并使用!访问变量!像这样的人物.FYI endlocal关闭了效果.

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

正如您所看到的,我的第一个示例更容易编码,但我的第二个示例更易于阅读.无论您使用哪种方法,都取决于您的需求和可重用性.

setlocal命令还具有创建在命令之后死亡的临时变量的效果endlocal.这意味着您不需要在批处理文件结束时删除它们,并将执行期间更改的任何变量恢复为原始值.这很好,因为您不必担心"踩踏"任何预先存在的变量.