我们有一堆.bat
构建脚本,由基于PowerShell的GitLab runner调用,最近这些脚本从以下形式进行了重构:
program args
if !errorlevel! neq 0 exit /b !errorlevel!
更简洁地说:
program args || exit /b
今天我调查了一个构建作业,显然如果你看错误日志,该作业失败了,但被报告为成功。经过多次尝试,我发现这种模式并不总是按预期工作:
program args || exit /b
但是当前面的方法不起作用时,这个方法似乎有效:
program args || exit /b !errorlevel!
我已经阅读了这个Windows批处理中关于选项b的退出方式,带或不带错误级别的SO问题以及来自https://www.robvanderwoude.com/exit.php的下面陈述,但仍然不能完全解释我观察到的现象。
DOS在线帮助(HELP EXIT)并未明确说明/B参数退出当前脚本实例,但并不一定是退出当前脚本。也就是说,如果脚本在被CALL的代码段中,EXIT /B将退出CALL而不是脚本本身。
这是我用来探索这个问题的最小批处理文件:
@echo off
setlocal EnableDelayedExpansion
cmd /c "exit 99" || exit /b
:: cmd /c "exit 99" || exit /b !errorlevel!
这是我如何调用批处理文件的方式(模拟GitLab PowerShell Runner调用它的方式):
& .\test.bat; $LastExitCode
这取决于批处理文件中执行哪一行,以下是输出结果:
PS> & .\test.bat; $LastExitCode
0
PS> & .\test.bat; $LastExitCode
99
还有另一种获得正确行为的方式,即在PowerShell中使用CALL
完整地调用批处理文件:
PS> & cmd.exe /c "call .\test.bat"; $LastExitCode
99
虽然我欣赏这可能是从PowerShell调用批处理文件的正确方式,但根据我看到的许多示例,这似乎不是常识。此外,如果这是“正确的方法”,我想知道为什么PowerShell不会以这种方式调用批处理文件。最后,当省略
call
时,我仍然不明白为什么行为会因我们是否将!errorlevel!
添加到exit / b
语句而发生更改。更新: 谢谢大家的讨论,但我觉得问题可能已经偏离了轨道,这可能是我在原始问题中表述不够清晰导致的。如果可能的话,我想知道以下语句中errorlevel
在何时(被认为)被评估:
program || exit /b
它是否真的像这样在早期(即程序
运行之前)进行评估:
program || exit /b %errorlevel%
或者是惰性评估的(即在执行program
并在内部更新了errorlevel
后,在执行exit
时进行评估),更类似于这种情况:
program || exit /b !errorlevel!
因此,除非情况不容乐观,否则我并不追求猜测。即使这样,知道没有确定的答案或者是一个错误也可以成为我的可接受答案: o)。
因此,我并不追求猜测。如果逼不得已,知道没有明确的答案或者是个bug也是可以接受的 :o)。
ErrorLevel
的延迟扩展,否则你将得到先前行的值,这在你的情况下将是零。 - jwdonahueerrorlevel
的值,但是它必须对其进行评估,并且在prog || exit
语句中,评估的关键点就是我的问题所在。 - Chris Oldwoodcommand.com
和cmd.exe
中存在许多意外行为,尽管微软不愿修复其中大部分,但他们似乎也不想记录这些问题。例如,使用::
作为注释而导致的坏标签错误。因此,我逐渐收集了一些脚本,其唯一目的就是阐明实际行为。 - jwdonahueprogram || exit /b
的工作方式类似于program || exit /b !errorlevel!
(假设启用了setlocal enabledelayedexpansion
),但是 - 关于设置_cmd.exe_进程退出代码 - 仅在使用call
调用批处理文件时才有效。如果没有call
,exit /b
的错误级别意外地不确定cmd.exe
的进程退出代码(它最终变为0
,即使在会话内部错误级别已经被设置,但这在您的情况下不相关)。但是,exit /b <code>
- 即一个 _ 明确的_退出代码 - 总是会设置_cmd.exe_进程的退出代码。 - mklement0call
的情况下,exit /b
的错误级别意外地不能确定cmd.exe
的进程退出代码”是我从中得出的结论。非常感谢您的耐心! - Chris Oldwood