IF, CALL, EXIT and %ERRORLEVEL% in a .bat

11

请问有人可以帮我理解%ERRORLEVEL%变量的行为吗?为什么在一个IF语句中,在CALL之后它没有被设置,但是在ECHO %ERRORLEVEL%.2这一行中却存在?涉及到IT技术相关内容。

@ECHO OFF
SET ERRORLEVEL
VERIFY > NUL

ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU

IF %ERRORLEVEL% == 0 (
  ECHO %ERRORLEVEL%.1
  CALL :FOO
  ECHO %ERRORLEVEL%.2
  IF ERRORLEVEL 42 ECHO 42.3
)

GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF

标准输出

C:\Users\Ilya.Kozhevnikov\Dropbox>foo.bat
Environment variable ERRORLEVEL not defined
0.0
0.1
0.2
42.3

然而,如果没有IF语句,%ERRORLEVEL%变量就无法按预期设置。

@ECHO OFF
SET ERRORLEVEL
VERIFY > NUL

ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU

REM IF %ERRORLEVEL% == 0 (
  ECHO %ERRORLEVEL%.1
  CALL :FOO
  ECHO %ERRORLEVEL%.2
  IF ERRORLEVEL 42 ECHO 42.3
REM )

GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF

标准输出

C:\Users\Ilya.Kozhevnikov\Dropbox>foo.bat
Environment variable ERRORLEVEL not defined
0.0
0.1
42.2
42.3

可能是 windows batch SET inside IF not working 的重复问题。 - Laf
请查看我标记为重复的问题。这解释了您的脚本正在发生的情况,以及您需要做什么来解决问题。 - Laf
2个回答

13
当cmd解析器读取一行或一组行(括号内的代码)时,所有变量的读取都会在开始执行代码之前用变量内的值替换。如果代码块的执行更改了变量的值,则此值无法从同一块内部看到,因为变量上的读取操作不存在,而是被替换为变量中的值。
要解决这个问题,需要启用延迟扩展,并在需要时将语法从%var%更改为!var!,告诉解析器需要延迟读取操作,直到命令执行。
@ECHO OFF

setlocal enabledelayedexpansion

SET ERRORLEVEL
VERIFY > NUL

ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU

IF %ERRORLEVEL% == 0 (
  ECHO !ERRORLEVEL!.1
  CALL :FOO
  ECHO !ERRORLEVEL!.2
  IF ERRORLEVEL 42 ECHO 42.3
)

GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF

1
谢谢,我之前不知道!!的语法。 - Ilya Kozhevnikov

2

MC ND 已经很好地回答了这个问题。

以下是一段替代代码,展示了ERRORLEVEL的扩展和延迟扩展。

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
VERIFY > NUL

ECHO !ERRORLEVEL!.0 delayed
ECHO %ERRORLEVEL%.0 expanded
IF ERRORLEVEL 1 ECHO SNAFU

IF !ERRORLEVEL! == 0 (
  ECHO !ERRORLEVEL!.1 delayed
  ECHO %ERRORLEVEL%.1 expanded
  CALL :FOO
  ECHO !ERRORLEVEL!.2 delayed
  ECHO %ERRORLEVEL%.2 expanded
)
ENDLOCAL
GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF

微软在set命令的帮助文档中描述了延迟扩展的行为,可以在输入set /?help set后在命令提示符窗口中阅读。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接