gpt4 book ai didi

powershell - "|| exit/b"和 "|| exit/b !errorlevel!"的区别

转载 作者:行者123 更新时间:2023-12-03 14:35:54 63 4
gpt4 key购买 nike

我们有一堆 .bat构建脚本由基于 PowerShell 的 GitLab 运行程序调用,这些脚本最近从以下内容重构:

program args
if !errorlevel! neq 0 exit /b !errorlevel!
更简洁:
program args || exit /b
今天我调查了一个构建作业,如果您查看错误日志,该作业显然失败了,但报告为成功。经过大量实验,我发现这种模式并不总是按预期工作:
program args || exit /b
但是当前者没有时,这似乎确实有效:
program args || exit /b !errorlevel!

我已经阅读了 SO 问题 Windows batch exit option b with or without errorlevel以及以下来自 https://www.robvanderwoude.com/exit.php 的声明但仍然不能完全解释我在观察什么。

The DOS online help (HELP EXIT) doesn't make it clear that the /B parameter exits the current instance of script which is not necessarily the same as exiting the current script.I.e. if the script is in a CALLed piece of code, the EXIT /B exits the CALL, not the script.



这是我用来探索这个的最小批处理文件:
@echo off
setlocal EnableDelayedExpansion
cmd /c "exit 99" || exit /b
:: cmd /c "exit 99" || exit /b !errorlevel!
这就是我调用批处理文件的方式(以模拟基于 GitLab PowerShell 的运行程序如何调用它):
& .\test.bat; $LastExitCode
以下是根据批处理文件中两行中的哪一行执行的输出:
PS> & .\test.bat; $LastExitCode
0
PS> & .\test.bat; $LastExitCode
99

还有另一种获得正确行为的方法,即使用 CALL 从 PowerShell 中直接调用批处理文件。还有:
PS> & cmd.exe /c "call .\test.bat"; $LastExitCode
99
虽然我很欣赏这可能是从 PowerShell 调用批处理文件的正确方法,但根据我见过的许多示例,这似乎不是常识。我也想知道为什么 PowerShell 不以这种方式调用批处理文件,如果它是“正确的方式”。最后我还是不明白为什么,当离开 call 时,行为会根据我们是否添加 !errorlevel! 而改变。到 exit /b声明。

更新:感谢到目前为止的所有讨论,但我觉得它在杂草中迷失了,这可能是我的错,因为我的原始问题太含糊了。我认为我真正想要的(如果可能的话)是 明确声明 关于当 errorlevel在以下语句中(据说)进行评估:
program || exit /b
是否真的像这样早期评估(即在 program 运行之前):
program || exit /b %errorlevel%
或者它是否被懒惰地评估(即当 exitprogram 运行后执行并且内部 errorlevel 已更新时),更类似于:
program || exit /b !errorlevel!
因此,我并不是真的在猜测,除非遗憾的是,这是我们能做的最好的事情,在这种情况下,知道没有明确的答案或者这是一个错误对我来说是可以接受的答案:o)。

最佳答案

解决方法 :

  • 通过 cmd /c <batch-file> ... `& exit 调用您的批处理文件 ,在这种情况下 || exit /b没有显式退出代码的解决方案按预期工作。
  • cmd /c .\test.bat `& exit
  • 请注意 ` -逃脱& ,这会阻止 PowerShell 解释 &前面。省略 `如果您从不涉及 shell 的环境(例如从计划任务)运行命令。
  • 或者,您可以使用表格 cmd /c "<batch-file> ... & exit" ,但这需要转义任何 "作为参数一部分的字符(或使用 here-string )。如果没有使用 PowerShell 变量或表达式,则可以选择单引号来避免该问题:cmd /c '<batch-file> ... & exit'

  • 使用 cmd /c <batch-file> ... `& exit例行从外部调用批处理文件 cmd.exe建议 , 甚至没有明确的批处理文件 exit /b (或 exit )调用可能会出现意外行为 - 参见 this answer .

  • 或者 - 但前提是你的批处理文件永远不需要从另一个应该返回控制的批处理文件中调用,并且它永远不需要成为 cmd /c 的一部分。不是最后一个命令的多命令命令行[1] - 你可以使用 || exit而不是 || exit /b - 这将退出正在执行的 cmd.exe立即处理整个过程,但随后可靠地报告退出代码(错误级别)(至少在 <command> || exit 语句的上下文中)也可以从外部直接调用 cmd.exe ,例如 & .\test.bat (或者,在这个简单的情况下,只是 .\test.bat )来自 PowerShell。

  • 同时结合 setlocal EnableDelayedExpansionexit /b !ERRORLEVEL!也可以工作(除了在 (...) 内部 - 参见 this post ) - 由于使用了显式退出代码 - 它显然更麻烦并且可能有副作用,特别是悄悄删除 !来自命令的字符,例如 echo hi! (虽然可以通过将 setlocal EnableDelayedExpansion 调用放在 exit /b 调用之前的行上来最小化该问题,但如果有多个退出点,则需要重复)。

    cmd.exe的行为令人遗憾在这种情况下,但无法避免。
    从外部调用批处理文件时 cmd.exe :
  • exit /b - 没有退出代码(错误级别)参数 - 只设置 cmd.exe按预期处理退出代码 - 即批处理文件中最近执行的命令的退出代码 - 如果您跟随批处理文件调用 & exit ,即 cmd /c <batch-file> ... `& exit
  • 没有 & exit解决方法,无参数 exit /b来自批处理文件的调用反射(reflect)在 %ERRORLEVEL% 中可变内部- cmd.exe -session,但这不会转化为 cmd.exe的进程退出代码,然后默认为 0 .[1]
  • & exit解决方法,批处理文件内无参数 exit /b是否正确设置 cmd.exe的退出代码,即使在 <command> || exit /b声明,在这种情况下 <command>的退出代码按预期传递。

  • exit /b <code> ,即传递退出代码 <code>明确地,始终有效 [2],即 & exit然后不需要解决方法。
  • 这种区别是 可以合理地称为错误的模糊不一致 ; Jeb's helpful answer有演示行为的示例代码(在撰写本文时使用不太全面的 cmd /c call ... 解决方法,但它同样适用于 cmd /c "... & exit" )。

  • [1] 与 cmd /c ,可以传递多条语句执行,最后一条语句决定了 cmd.exe进程的退出代码。例如, cmd /c "ver & dir nosuch"报告退出代码 1 ,因为不存在的文件系统项 nosuch造成 dir将错误级别设置为 1 ,无论前面的命令 ( ver ) 是否成功。不一致之处在于,对于名为 test.bat 的批处理文件以 exit /b 退出没有明确的退出代码参数, cmd /c test.bat总是报告 0 , 而 cmd /c test.bat `& exit正确报告批处理文件退出之前执行的最后一条语句的退出代码。
    [2] 退出代码可以从字面上或通过变量指定,但陷阱是 - 由于 cmd.exe的前期变量扩展 - <command> || exit /b %ERRORLEVEL%无法按预期工作,因为 %ERRORLEVEL%此时扩展到此语句之前的错误级别,而不是由 <command> 设置的错误级别。 ;这就是延迟扩张的原因,通过运行 setlocal enabledelayedexpansion或已调用 cmd.exe/V选项,在这种情况下是必需的: <command> || exit /b !ERRORLEVEL!

    关于powershell - "|| exit/b"和 "|| exit/b !errorlevel!"的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66248276/

    63 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com