Exit /b 0 不将 %errorlevel% 设置为 0

Exit /b 0 不将 %errorlevel% 设置为 0

我在将批处理脚本中的错误级别设置为 0 时出现了一个奇怪的行为。

a.bat我正在Jenkins 作业上调用批处理脚本,该脚本又调用第二个脚本b.cmd并在调用后评估错误级别:

:: b.cmd
:: some stuff, but relevant is only this:
@echo b errorlevel: %errorlevel%
EXIT /B 0

“主要”脚本:

:: a.bat
pushd %CD%
cd..

@echo a errorlevel: %errorlevel%

set outputdir=".\some\exisiting\dir"
:: (1)
md %outpurdir%
@echo a errorlevel: %errorlevel%

:: (!)
if "$somevar" = "FOO" ( 
  cd .\WhereBIs

  :: (2)
  call :seterr 0
  @echo a errorlevel: %errorlevel%

  :: (3)
  call b.cmd

  @if %errorlevel% neq 0 (
    @echo a errorlevel: %errorlevel%
    set errmsg=Error calling b
    goto error
  )

  :: more stuff
)

:error
@echo %errmsg%
popd
:: (4)
@echo a errorlevel: %errorlevel%
@if %errorlevel% neq 0 exit %errorlevel%
Exit /B 1

:seterr
exit /b %1

(我借用:seterr这个问题

当我运行詹金斯作业时似乎发生了什么:

  1. md返回并将错误级别设置为 1,因为该目录已经存在。
  2. 调用:seterr没有达到预期的效果,错误级别仍然是 1
  3. 调用b.cmd完成没有问题,错误级别b为 0,但调用后错误级别a仍然1,在阅读了链接问题的答案后我绝对不会想到这一点。
  4. 跳转到:error并调用之后popd,错误级别突然重置为 0 - 这也是我没有想到的。

有人知道这里可能发生了什么吗?我没有意外地手动设置错误级别,因此它应该是系统变量,而不是用户定义的变量。

答案1

您没有显示整个脚本。我知道的唯一可能的解释是您的代码位于较大的括号内,可能是 FOR 循环或 IF 条件的一部分。

%ERRORLEVEL% 在解析行时被扩展,并且整个括号内的块同时被解析。因此,您看到的 ERRORLEVEL 必须在最外层括号开始之前就存在。

如果您想看到代码块内的变化值,则应该使用延迟扩展。

以下是一个简单的演示:

@echo off
setlocal enableDelayedExpansion
set var=BEFORE
(
  set var=AFTER
  echo Normal expansion shows value before block started: %var%
  echo Delayed expansion shows the current value: !var!
)

- 输出 -

Normal expansion shows value before block started: BEFORE
Delayed expansion shows the current value: AFTER

答案2

虽然这个请求已经得到解决,但还有另一个原因导致上述行为。例如,将其放入批处理文件中并运行:

@set errorlevel=
@dir >nul
@if %errorlevel% equ 0 (echo 1: Correctly detected: No error!) else echo.
@if not errorlevel 1 (echo A: Correctly detected: No error!) else echo.
@dir nonexistent >nul
@if %errorlevel% neq 0 (echo 2: Correctly detected: An error!) else echo.
@if errorlevel 1 (echo B: Correctly detected: An error!) else echo.

@set errorlevel=7
@dir >nul
@if %errorlevel% equ 0 (echo 3: Correctly detected: No error!) else echo.
@if not errorlevel 1 (echo C: Correctly detected: No error!) else echo.
@dir nonexistent >nul
@if %errorlevel% neq 0 (echo 4: Correctly detected: An error!) else echo.
@if errorlevel 1 (echo D: Correctly detected: An error!) else echo.

如果你观察这批输出,以 3: 开头的行将会丢失,而以 4: 开头的行将会是恶作剧。

结论:不要使用 %errorlevel% 来评估错误级别,而是使用 if errorlevel。

相关内容