我正在编写一些 PowerShell 脚本来进行一些构建自动化。我在这里找到了echo $? 根据前面的语句返回真或假。我刚刚发现 echo 是Write-Output的别名。写主机 $? 也有效。但是我还是不清楚这个$是怎么回事?作品。有人可以对这个说几句话吗。正在寻找回声 $? 在网上没有给我太多。
2 回答
用更详细的信息补充Martin Brandl 的有用答案:
tl;博士
自动变量
$?
(请参阅Get-Help about_Automatic Variables
)包含一个布尔值,它反映最近的语句中是否发生了任何非终止错误。- 由于
$?
在每个语句之后设置,因此您必须在感兴趣的语句之后立即检查它,或者将其保存以供以后检查。 - 有关可能违反直觉的行为,请参见下文。
- 由于
自动变量通过记录最近执行的外部命令行实用程序(例如)的特定退出代码来补充这一点。
$LASTEXITCODE
findstr
$LASTEXITCODE
补充$?
,$?
仅反映外部实用程序的抽象0
成功或失败 - 退出代码映射到$True
,任何非零退出代码到$False
- 而$LASTEXITCODE
包含实际退出代码。- 由于
$LASTEXITCODE
仅为外部命令行实用程序设置,因此它的值通常比在每个语句$?
之后设置的有效时间长。
关于如何设置,以及它的值究竟表明了什么,有许多微妙之处:$?
$?
仅反映非终止错误的发生,因为默认情况下(更罕见的)终止错误会终止当前命令行/脚本的执行,并且要处理它们,您需要使用try / catch
(首选)或trap
(参见Get-Help about_Try_Catch_Finally
andGet-Help about_Trap
)。- 相反,您可以选择将非终止错误视为终止错误,使用首选项变量
$ErrorActionPreference
或通用 cmdlet 参数
-ErrorAction
(别名-EA
) - 请参阅Get-Help about_Preference_Variables
和Get-Help about_CommonParameters
。
- 相反,您可以选择将非终止错误视为终止错误,使用首选项变量
除非明确忽略(使用 common
-ErrorAction Ignore
cmdlet 参数),否则所有非终止错误(和捕获的终止错误)都会$Error
按时间倒序收集在自动收集中;也就是说,元素$Error[0]
包含最近的错误。对于传递了多个输入对象的命令,
$?
包含$False
仅告诉您处理至少一个输入对象失败。换句话说:输入对象的任何子集(包括所有对象)都可能发生错误。- 要确定准确的错误计数和有问题的输入对象,您必须检查
$Error
集合。
- 要确定准确的错误计数和有问题的输入对象,您必须检查
对于传递目标命令执行的非远程间接执行cmdlet - 例如
Invoke-Expression
,Start-Process
和Start-Job
不Invoke-Command
带-ComputerName
参数(不涉及远程处理 - 见下文) -仅反映原则上$?
是否可以调用目标命令,无论该命令随后是否报告错误。- 一个简单的例子:
Invoke-Expression '1 / 0'
设置$?
为$True
(!),因为Invoke-Expression
能够解析和调用表达式,即使表达式本身随后失败。 - 同样,检查
$Error
集合会告诉您目标命令是否报告了错误以及报告了哪些错误。
- 一个简单的例子:
使用远程处理(总是间接执行)cmdlet,尤其是使用
Invoke-Command
参数-ComputerName
(这是典型的),以及隐式远程处理 cmdlet,$?
确实反映了目标命令是否报告了任何错误。一个简单的例子(必须从提升的控制台运行并假设本地机器已经设置为远程处理):
Invoke-Command -ComputerName . { 1 / 0 }
因为涉及远程处理,确实设置$?
为$False
反映目标命令的失败1 / 0
。
请注意,尽管本地计算机 (.
) 是目标计算机,但使用-ComputerName
总是使用远程处理。请注意,根据设计,远程处理将远程发生的正常终止错误报告为非终止错误,大概是这样一个目标机器上的正常终止错误不会中止所有其他机器上的处理。
确实反映以下错误的命令示例
$?
:# Invoking a non-existing cmdlet or utility directly. NoSuchCmd # Ditto, via call operator &. # Note, however, that using a *script block* with & behaves differently - see below. & 'NoSuchCmd' # Invoking a cmdlet with invalid parameter syntax. Get-ChildItem -NoSuchParameter # Invoking a cmdlet with parameter values that cause a (non-terminating) runtime error. Get-ChildItem NoSuchFile # Invoking an external utility that reports a nonzero exit code. findstr -nosuchoptions # The specific exit code is recorded in $LASTEXITCODE, # until the next external utility is called. # Runtime exceptions 1 / 0 # A cmdlet that uses remoting: # (Must be run from an elevated session, and the local machine must # be configured for remoting first - run `winrm quickconfig`). # Note that remoting would NOT be involved WITHOUT the -ComputerName parameter, # in which case `$?` would only reflect whether the script block could be # _invoked_, irrespective of whether its command(s) then fail or not. Invoke-Command -ComputerName . { 1 / 0 } # A .NET method that throws an exception. # Note: Outside of a `try/catch` handler, this is a non-terminating error. # Inside a `try/catch` handler, .NET exceptions are treated as terminating # and trigger the `catch` block. [System.IO.Path]::IsPathRooted('>')
不反映错误的命令示例
$?
:<# Non-remoting indirect execution cmdlets: $? reflects only whether the specified command could be *invoked*, irrespective of whether the command itself then failed or not. In other words: $? is only $False if the specified command could not even be executed, such as due to invalid parameter syntax, an ill-formed target command, or a missing target executable. #> # Invoking a command stored in a script block. & { 1 / 0 } # Invoking an expression stored in a string. Invoke-Expression '1 / 0' # Starting a background job. Start-Job { 1/ 0 } # The *non-remoting* form of Invoke-Command (WITHOUT -ComputerName). Invoke-Command { 1 / 0 }
您可以在此处找到完整的标点符号表。答案(取自图表):
上一次操作的执行状态($true 或 $false);与报告最后执行的基于 Windows 的程序的退出代码的 $LastExitCode 形成对比。