如何在 cmd /c 中设置 %ERRORLEVEL%?

Cod*_*ggo 2 powershell cmd exit-code errorlevel delayedvariableexpansion

我希望能够在PowerShell中运行的命令提示符脚本(即)的开头将%ERRORLEVEL%环境变量(也称为“系统变量”)设置为任意值。每当人们想要设置(1)时,他们都会执行以下操作:cmd /c%ERRORLEVEL%

cmd /c "exit /b 3"
cmd /c "echo %ERRORLEVEL%" 
Run Code Online (Sandbox Code Playgroud)

但是,尽管在正常命令提示符中运行上述命令时%ERRORLEVEL%设置为3,但如果在 PowerShell 中执行这些确切的行,则退出代码环境变量不会设置3并保持为0。此外,您不能执行以下操作:

cmd /v:on /c "exit /b 3 & echo !ERRORLEVEL!"
Run Code Online (Sandbox Code Playgroud)

exit命令完全脱离命令执行(即),并且在运行cmd /c后没有其他命令。&

因此,我尝试在PowerShell中执行以下命令:

cmd /v:on /c "SET %ERRORLEVEL% = 4 & echo !ERRORLEVEL!"
Run Code Online (Sandbox Code Playgroud)

预期输出是4,但这总是输出0。我不明白为什么我无法使用SET环境%ERRORLEVEL%变量。我已经使用了延迟命令执行(示例在这里),但这里似乎没有任何摆弄。

有谁知道为什么该命令SET %ERRORLEVEL% = 4不起作用?

如果您无法使用SET环境变量,那么如何设置%ERRORLEVEL%为像上面这样用与号 ( ) 分隔的命令字符串中的任意值&

mkl*_*nt0 6

如果您想将最终的退出代码存储在cmd.exe变量中以供以后使用exit不要尝试设置ERRORLEVEL;相反,使用自定义变量名称;例如,ec退出代码):

\n\n
# Execute in PowerShell\nPS> cmd /v /c \'set "ec=3" & echo ... & exit /b !ec!\'; $LASTEXITCODE\n...\n3\n
Run Code Online (Sandbox Code Playgroud)\n\n

cmd.exe一边:

\n\n
    \n
  • set "ec=3"将变量设置ec为值3

    \n\n
      \n
    • 将名称-值对括起来"..."并不是绝对必要的,但可以清楚地描述值的结尾,并允许使用带有嵌入特殊字符(例如 )的值&

    • \n
    • 变量的稍后可以被引用为%ec%预先扩展)或!ec!延迟扩展,如果通过setlocal enabledelayedexpansion或通过命令行开关启用/v- 请参阅help setlocal

    • \n
  • \n
  • echo ...是代表更多命令的示例命令

  • \n
  • exit /b !ec!以变​​量的值ec作为退出代码退出;请注意该变量如何通过延迟扩展必然被引用为 ,!ec!而不是,因为该变量被设置为同一语句的一部分%ec%

    \n\n
      \n
    • 无论您是否使用/b(仅退出当前批处理文件),这里都没有什么区别;无论哪种方式,exit本例中的语句都确定实例的进程退出代码cmd
    • \n
  • \n
\n\n

这些命令使用运算符作为单个语句的一部分进行排序(无条件一个接一个地执行) 。&

\n\n

在 PowerShell 端:

\n\n
    \n
  • PowerShell 与 \ 的类似cmd.exe&语句分隔符;-它允许您将多个语句放在一行上。

  • \n
  • $LASTEXITCODE是包含最近执行的外部程序的进程退出代码的自动 PowerShell 变量,在本例中为cmd.exe\'s,值为3

  • \n
\n\n
\n\n
\n

有谁知道为什么该命令SET %ERRORLEVEL% = 4不起作用?

\n
\n\n

总结有关该问题的评论中的有用信息:

\n\n
    \n
  • 从根本上讲,不要尝试设置动态(伪)环境变量%ERRORLEVEL%- 它是由自动维护的,cmd.exe以反映最近命令的退出代码 - 请参阅底部部分。

  • \n
  • 不要=cmd.exe变量赋值中添加空格:

    \n\n
      \n
    • 之前的=空格成为变量名称的一部分
    • \n
    • 后面的空格成为value 的一部分
    • \n
  • \n
  • 不要将目标变量名称括起来%...%(除非您想通过另一个其值包含要分配的变量名称的变量来间接设置变量

  • \n
\n\n
\n

set %ERRORLEVEL% = 4

\n
\n\n

通过在命令序列的开头%ERRORLEVEL%进行反射,上面的赋值创建了一个按字面意思命名的变量(即,值后跟一个空格),其值为(即,后跟一个空格)。0 0\xc2\xa0%ERRORLEVEL%\xc2\xa044

\n\n
\n\n

中的变量cmd.exe

\n\n

基本上,除了下面讨论的例外情况,中的变量cmd.exe都是环境变量

\n\n

与 Bash 和 PowerShell 等 shell 不同,子进程看不到的shell局部变量没有单独的命名空间。

\n\n

这具有以下含义:

\n\n
    \n
  • 预定义的持久环境变量(例如%Path%与您使用命令定义的自定义变量共享相同的命名空间)SET,因此您必须注意名称冲突。

  • \n
  • 同样,您从会话/批处理文件运行的子进程继承您在会话中创建的自定义变量。cmd.exe

    \n\n
      \n
    • 请注意,使用setlocal不会改变这一点;setlocal是一种cmd内部作用域机制,允许您控制自定义环境变量的生命周期,方法是将它们本地化到调用的作用域(批处理文件)setlocal,并通过后续endlocal调用或隐式地在封闭的末尾删除它们批处理文件。
    • \n
  • \n
\n\n

自定义变量是进程专用的环境变量,超出了进程的范围cmd.exe持久环境变量定义必须通过注册表(例如使用实用程序)创建和修改setx.exe

\n\n

除了预定义(持久)环境变量和自定义(仅限会话)环境变量之外,cmd.exe还维护动态伪环境变量,例如%ERRORLEVEL%%RANDOM%(参见下面的列表):

\n\n
    \n
  • 这些伪环境变量具有自己维护的动态cmd.exe值......

  • \n
  • ...并且它们对子进程不可见。

  • \n
\n\n

注意:严格来说,这些动态变量仅在所谓的命令扩展打开时启用,但默认情况下是这样(您可以使用 禁用它们/E:OFF,但这是不明智的)。

\n\n

由于这些动态变量严格来说并不是子进程继承其副本的进程环境的一部分,因此它们不是环境变量,尽管help SET有些令人困惑地将它们称为动态环境变量

\n\n

您不应该(也不能)修改这些变量。

\n\n

如果您尝试,真正发生的情况是您使用真正的自定义环境变量隐藏(覆盖)这些伪变量,根据定义,这些变量具有静态值。

\n\n

因此,稍后依赖该名称的变量来实现其通常的动态行为的代码可能会出现故障。

\n\n

动态变量列表,在 Windows 10 上通过help SET(添加强调)检索:

\n\n
\n

如果启用了命令扩展,则有几个可以扩展的动态环境变量,但它们不会显示在 显示的变量列表中SET。每次扩展变量值时 都会动态计算这些 变量值。\n如果用户使用这些名称之一显式定义变量,则该定义将覆盖下面描述的动态变量:

\n\n
    \n
  • %CD%- 扩展到当前目录字符串。
  • \n
  • %DATE%- 使用与 DATE 命令相同的格式扩展到当前日期。
  • \n
  • %TIME%- 使用与 TIME 命令相同的格式扩展到当前时间。
  • \n
  • %RANDOM%- 扩展为 0 到 32767 之间的随机十进制数。
  • \n
  • %ERRORLEVEL%- 扩展到当前的 ERRORLEVEL 值
  • \n
  • %CMDEXTVERSION%- 扩展为当前命令处理器扩展\n 版本号。
  • \n
  • %CMDCMDLINE%- 扩展到调用命令处理器的原始命令行。
  • \n
  • %HIGHESTNUMANODENUMBER%- 扩展到该计算机上\n 的最高 NUMA 节点号。
  • \n
\n
\n