1

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

cmd /c "exit /b 3"
cmd /c "echo %ERRORLEVEL%" 

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

cmd /v:on /c "exit /b 3 & echo !ERRORLEVEL!"

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

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

cmd /v:on /c "SET %ERRORLEVEL% = 4 & echo !ERRORLEVEL!"

预期的输出是4,但这总是输出0。我无法弄清楚为什么我无法SET使用%ERRORLEVEL%环境变量。我使用了延迟命令执行(这里的例子),但这里似乎没有多少摆弄。

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

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

4

1 回答 1

4

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

# Execute in PowerShell
PS> cmd /v /c 'set "ec=3" & echo ... & exit /b !ec!'; $LASTEXITCODE
...
3

cmd.exe侧面:

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

    • 将名称-值对包含在其中"..."并不是绝对必要的,但可以清楚地描述值的结尾,并允许使用带有嵌入特殊字符的值,例如&.

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

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

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

    • 是否使用/b(仅退出当前批处理文件)在这里没有区别;无论哪种方式,exit这种情况下的语句都会确定实例的进程退出代码cmd

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

在 PowerShell 方面:

  • cmd.exePowerShell 与's的类似物&语句分隔符- 它允许您将多个语句放在一行上。;

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


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

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

  • 从根本上说,不要尝试设置动态(伪)环境变量%ERRORLEVEL%——它会自动维护cmd.exe以反映最新命令的退出代码——见底部。

  • 不要=cmd.exe变量赋值中放置空格:

    • 成为变量名的一部分之前的空格。=
    • 之后的空格成为value 的一部分
  • 不要将目标变量名包含在其中%...%(除非您想通过另一个变量间接设置一个变量,该变量的包含要分配给的变量的名称)。

set %ERRORLEVEL% = 4

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


中的变量cmd.exe

从根本上说,除了下面讨论的例外,变量cmd.exe都是环境变量

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

这具有以下含义:

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

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

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

自定义变量是超出流程范围的仅限流程的环境变量cmd.exe;必须通过注册表创建和修改持久性环境变量定义,例如使用实用程序。setx.exe

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

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

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

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

因为这些动态变量严格来说不是子进程继承其副本的进程环境的一部分,所以它们不是环境变量,尽管help SET有些混淆地称它们为动态环境变量

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

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

因此,依赖于该名称的变量以具有其通常的动态行为的后续代码可能会出现故障。

在 Windows 10 上通过以下方式检索到的动态变量列表help SET(强调):

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

  • %CD%- 扩展到当前目录字符串。
  • %DATE%- 使用与 DATE 命令相同的格式扩展到当前日期。
  • %TIME%- 使用与 TIME 命令相同的格式扩展到当前时间。
  • %RANDOM%- 扩展为 0 到 32767 之间的随机十进制数。
  • %ERRORLEVEL%- 扩展到当前的 ERRORLEVEL 值
  • %CMDEXTVERSION%- 扩展到当前的命令处理器扩展版本号。
  • %CMDCMDLINE%- 扩展到调用命令处理器的原始命令行。
  • %HIGHESTNUMANODENUMBER%- 扩展到这台机器上最高的 NUMA 节点号。
于 2020-02-29T04:33:01.667 回答