我在将批处理脚本中的错误级别设置为 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
了这个问题)
当我运行詹金斯作业时似乎发生了什么:
md
返回并将错误级别设置为 1,因为该目录已经存在。- 调用
:seterr
没有达到预期的效果,错误级别仍然是 1 - 调用
b.cmd
完成没有问题,错误级别b
为 0,但调用后错误级别a
为仍然1,在阅读了链接问题的答案后我绝对不会想到这一点。 - 跳转到
: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。