执行命令时如何忽略PowerShell中的特定错误? [英] How to ignore specific error in PowerShell when executing a command?
问题描述
我知道 ErrorAction
参数,还有 $ ErrorActionPreference
, $ Error
和 $
。
上下文
我要解决的问题是,当运行外部命令(例如choco或git)时,至少在我的任务上下文中,它给出应警告或什至不警告的错误。
由于其退出代码,PowerShell认为该结果在任何意义上都是错误,例如将红色写到输出等,这在我的任务上下文中是不希望的。 / p>
我可以使用 -ErrorAction
或 2>抑制这些命令的错误输出。 $ null
,但是我对使用这种特定命令完全消除任何错误感到沮丧。
我只想忽略那种已知的对我来说这不是问题类型的错误。
问题
是否有任何方法可以处理命令的错误而忽略某些特定错误,但通常会处理所有其他错误情况?
-
在常规控制台窗口中 ,在PowerShell v3及更高版本中, stderr行的输出与标准输出行相同。
-
这是可取的,因为许多程序都使用 stderr来报告真正的错误,但所有不是数据,例如状态消息。
-
Stderr行(除非已重定向-参见下文) )直接通过控制台进行打印(而标准行则发送到PowerShell的成功输出流中, y可以收集在变量中,可以通过管道发送,也可以通过
/
/>
重定向) 。
-
-
遗憾的是,即使在v5中, PowerShell ISE .1 , 以 red 格式打印stderr行,格式与PowerShell错误相同。
-
性能良好的控制台应用程序仅使用其退出代码来表示成功(退出代码
0
)与失败(任何非零退出代码)。 PowerShell将最近调用的控制台应用程序的退出代码保存在其自动$ LASTEXITCODE
变量中。 -
顺便说一句:
- 常用参数
-ErrorAction
和-ErrorVariable
不能与外部程序一起使用。 - 类似地,首选项变量
$ ErrorActionPreference
无效(意外除外,原因是此错误,从PowerShell v5.1 / PowerShell Core 6.2.0-preview.4开始)。 -
try
/catch
不能用于检测和处理外部程序的故障。 - 有关PowerShell复杂错误的全面概述处理规则,请参见此GitHub文档版本。
- 常用参数
注意:在下面的示例中,我使用以下外部命令,它们会产生1行stdout和1行stderr输出(请注意,重定向> & 2
由 cmd
而不是PowerShell处理,因为它位于'...'
;它用于产生stderr输出):
cmd / c’echo stdout& echo stderr&& 2'
一种使命令信号失败的变体,通过非零退出代码( exit 1
):
cmd / c'echo标准输出& echo stderr& 2&出口1'
因此, 通常满足以下条件即可:
$ stdOut = cmd / c'echo stdout&如果($ LASTEXITCODE -ne 0){抛出 cmd失败,则echo stderr&& 2’#std * err *将打印到控制台
。 }#处理错误
这会捕获变量<$ c $中的 stdout 输出c> $ stdout 并将 stderr 输出传递到控制台。
如果您要收集以后 的stderr输出,并且仅在出现错误 时显示它们:
$ stdErr = @()#初始化用于收集stderr行的数组。
#捕获标准输出,同时在$ stdErr中收集标准输出。
$ stdOut = cmd / c'echo stdout& echo stderr& 2&退出1’2>& 1 |哪里对象{
$ fromStdErr = $ _-是[System.Management.Automation.ErrorRecord]
if($ fromStdErr){$ stdErr + = $ _。ToString()}
-不是$ fromStdErr#仅当来自stdout
时才输出行}
#引发错误,其中包括收集的stderr行。
if($ LASTEXITCODE -ne 0){
抛出 cmd失败,并显示以下消息:$ stdErr
}
-
请注意
2>& 1
重定向,该操作指示PowerShell通过管道发送stderr行(流2
,错误流)(流1
,成功流) -
在
Where-Object
块中,$ _-是[System.Management.Automation.ErrorRecord]
用于标识 stderr 行,因为PowerShell在此类实例中包装了这些行。
或者,您可以将stderr输出收集在临时文件( 2> / path / to / tmpfile
),读取其内容并将其删除。
此GitHub问题建议引入在变量中收集重定向的stderr输出的选项,类似于您如何通过通用参数
-ErrorVariable
要求 cmdlet 收集变量中的错误。
有两个腔室:
-
固有地,仅打印stderr在以后行中,相对于 stdout 输出的特定上下文可能会丢失。
-
由于从Windows PowerShell v5.1 / PowerShell Core 6.2.0开始的 bug / a>,
$ ErrorActionPreference =停止
必须生效,因为2>& 1 然后,一旦收到第一条stderr行,code>重定向就会触发脚本终止错误。
如果您要在接收到的stderr行上有选择地采取行动 :
注意:
-
从本质上讲,当您处理在行中,您尚不知道该程序最终将报告失败还是成功。
-
$ ErrorActionPreference = 停止
警告也适用于此。
以下示例过滤掉stderr行 stderr1
并将 stderr2
行以红色打印到控制台(仅文本,不像PowerShell错误)。
$ stdOut = cmd / c'echo stdout&回声stderr1& 2& echo stderr2& 2’2>& 1 |
ForEach-Object {
if($ _ -is [System.Management.Automation.ErrorRecord]){#stderr行
$ stdErrLine = $ _。ToString()
开关-regex($ stdErrLine){
'stderr1'{break}#如果行包含'stderr1',则忽略
默认{Write-Host -ForegroundColor Red $ stdErrLine}
}
} else {#标准输出行
$ _#通过
}
}
#处理错误。
if($ LASTEXITCODE -ne 0){抛出 cmd失败。 }
I am aware ErrorAction
argument, also $ErrorActionPreference
,$Error
and $
.
Context
The issue I would like to solve is when running an external command (eg choco or git) it gives error which should be warning or not even warning, at least in my task context.
Because of their exit code PowerShell considers that result as error in any sense, for example writes out red to output, etc, which is not desirable in my task's context.
I can suppress those commands error output with -ErrorAction
or 2> $null
, but I have a bad feeling about completely vanishing any errors this way of the particular command.
I would like only ignore that known "not a problem in this context for me" type error.
Question
Is there any way to handle a command's error ignore some specific, but treat normally all other error conditions?
In a regular console window, in PowerShell v3 and above, stderr lines print just like stdout lines.
This is desirable, because stderr is used by many programs not just to report genuine errors, but anything that is not data, such as status messages.
Stderr lines (unless redirected - see below) print straight through the console (whereas stdout lines are sent to PowerShell's success output stream, where they can be collected in a variable, sent through the pipeline, or redirected with
>
/>>
).
Regrettably, the PowerShell ISE, even in v5.1, does print stderr lines in red, in the same format as PowerShell errors.
- Visual Studio Code with the PowerShell extension doesn't have this problem, and is worth migrating to in general, given that all future development effort will focus there, and given that it also works with the cross-platform PowerShell Core edition.
Well-behaved console applications solely use their exit code to signal success (exit code
0
) vs. failure (any nonzero exit code). PowerShell saves the exit code of the most recently invoked console application in its automatic$LASTEXITCODE
variable.As an aside:
- Common parameters
-ErrorAction
and-ErrorVariable
cannot be used with external programs. - Similarly, preference variable
$ErrorActionPreference
has no effect (except accidentally, due to this bug, as of PowerShell v5.1 / PowerShell Core 6.2.0-preview.4). try
/catch
cannot be used to detect and handle an external program's failure.- For a comprehensive overview of PowerShell's complex error handling rules, see this GitHub docs issue.
- Common parameters
Note: I'm using the following external commands in the examples below, which produce 1 line of stdout and 1 line of stderr output (note that the redirection >&2
is handled by cmd
, not PowerShell, because it is inside the '...'
; it is used to produce stderr output):
cmd /c 'echo stdout & echo stderr >&2'
A variant that makes the command signal failure, via a nonzero exit code (exit 1
):
cmd /c 'echo stdout & echo stderr >&2 & exit 1'
Therefore, normally the following should suffice:
$stdOut = cmd /c 'echo stdout & echo stderr >&2' # std*err* will print to console
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." } # handle error
This captures stdout output in variable $stdout
and passes stderr output through to the console.
If you want to collect stderr output for later and only show them in case of error:
$stdErr = @() # initialize array for collecting stderr lines.
# Capture stdout output while collecting stderr output in $stdErr.
$stdOut = cmd /c 'echo stdout & echo stderr >&2 & exit 1' 2>&1 | Where-Object {
$fromStdErr = $_ -is [System.Management.Automation.ErrorRecord]
if ($fromStdErr) { $stdErr += $_.ToString() }
-not $fromStdErr # only output line if it came from stdout
}
# Throw an error, with the collected stderr lines included.
if ($LASTEXITCODE -ne 0) {
Throw "cmd failed with the following message(s): $stdErr"
}
Note the
2>&1
redirection, which instructs PowerShell to send stderr lines (stream2
, the error stream) through the pipeline (stream1
, the success stream) as well.In the
Where-Object
block,$_ -is [System.Management.Automation.ErrorRecord]
is used to identify stderr lines, because PowerShell wraps such lines in instances of that type.
Alternatively, you could collect stderr output in a temporary file (2>/path/to/tmpfile
), read its contents, and delete it.
This GitHub issue proposes introducing the option of collecting redirected stderr output in a variable, analogous to how you can ask cmdlets to collect errors in a variable via common parameter -ErrorVariable
.
There are two caveats:
Inherently, by only printing stderr lines later, the specific context relative to the stdout output may be lost.
Due to a bug as of Windows PowerShell v5.1 / PowerShell Core 6.2.0,
$ErrorActionPreference = Stop
mustn't be in effect, because the2>&1
redirection then triggers a script-terminating error as soon as the first stderr line is received.
If you want to selectively act on stderr lines as they're being received:
Note:
Inherently, as you're processing the lines, you won't yet know whether the program will report failure or success in the end.
The
$ErrorActionPreference = 'Stop'
caveat applies here too.
The following example filters out stderr line stderr1
and prints line stderr2
to the console in red (text only, not like a PowerShell error).
$stdOut = cmd /c 'echo stdout & echo stderr1 >&2 & echo stderr2 >&2' 2>&1 |
ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) { # stderr line
$stdErrLine = $_.ToString()
switch -regex ($stdErrLine) {
'stderr1' { break } # ignore, if line contains 'stderr1'
default { Write-Host -ForegroundColor Red $stdErrLine }
}
} else { # stdout line
$_ # pass through
}
}
# Handle error.
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." }
这篇关于执行命令时如何忽略PowerShell中的特定错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!