我正在编写一些PowerShell脚本,用于构建自动化。我在这里找到了一个答案,链接,其中echo $?会根据上一个语句返回true或false。我刚刚发现echo是Write-Output的别名。Write-Host $?也可以工作。但我还不清楚这个$?是如何工作的。有人可以友善地说几句吗?在网上搜索echo $?并没有给我带来太多收获。
为了补充 Martin Brandl的有用回答,以下提供更详细的信息:
简而言之
自动变量$?
(参见Get-Help about_Automatic Variables
)包含一个布尔值,反映最近语句中的任何非终止错误是否发生。
$?
在每个语句后设置,因此您必须在感兴趣的语句之后立即检查它,或将其保存以供以后检查。自动变量$LASTEXITCODE
通过记录最近执行的外部命令行实用程序的特定退出代码(控制台应用程序,例如findstr
)来补充这一点。
$LASTEXITCODE
作为补充说明$?
,因为$?
仅反映外部实用程序的抽象成功或失败 - 将退出代码0
映射到$True
,将任何非零退出代码映射到$False
。而$LASTEXITCODE
包含实际的退出代码。$LASTEXITCODE
仅适用于外部命令行实用程序,因此其值通常比$?
更长时间有效。关于如何设置$?
以及它的值表示什么,有许多微妙之处:
$?
存在外部命令行实用程序 误报的风险,即使 $LASTEXITCODE
是 0
,也会报告 $false
,具体情况可以参见此答案。
$?
只反映了非终止性错误的发生,因为(较为罕见的)终止性错误默认会终止当前命令行/脚本的执行。要处理这些错误,您需要使用 try / catch
(首选)或 trap
(请参见Get-Help about_Try_Catch_Finally
和 Get-Help about_Trap
)。$ErrorActionPreference
或常用 cmdlet 参数 -ErrorAction
(别名 -EA
),详情请参见Get-Help about_Preference_Variables
和 Get-Help about_CommonParameters
。-ErrorAction Ignore
cmdlet 参数忽略,否则所有非终止性错误(和已捕获的终止性错误)都将被收集在自动的 $Error
集合中,以时间顺序倒序排列;也就是说,元素 $Error[0]
包含了最近的错误。$?
只告诉您至少有一个输入对象处理失败。换句话说:任何子集的输入对象都可能发生错误,包括全部输入对象。
要确定确切的错误计数和引起错误的输入对象,您必须检查 $Error
集合。Invoke-Expression
、Start-Process
和 Start-Job
以及不带 -ComputerName
参数的 Invoke-Command
(不涉及远程操作-请参见下文),$?
只反映了目标命令是否能够原则上被调用,不管该命令是否报告错误。Invoke-Expression '1/0'
将设置 $?
为 $True
(!),因为 Invoke-Expression
能够解析和执行表达式,即使表达式本身失败。$Error
集合会告诉您目标命令是否报告了错误以及错误内容。-ComputerName
参数的 Invoke-Command
(通常是这样的),
Examples of commands that DO reflect errors in $?
:
# 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('>')
Examples of commands that DO NOT reflect errors in $?
:
<#
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 相对比。