如何在 PowerShell 中写入标准错误?

发布于 2024-10-17 09:29:07 字数 329 浏览 3 评论 0原文

我无法弄清楚如何回显标准错误流并重定向可执行文件的错误流。

我来自 Bourne shellKorn shell 背景,我会使用它;

# Write to stderr
echo "Error Message!" >&2

# Redirect stderr to file
/do/error 2>/tmp/err.msg

I'm having trouble figuring out how to both echo to the standard error stream and redirect the error stream of an executable.

I have come from a Bourne shell and Korn shell background, of which I would use;

# Write to stderr
echo "Error Message!" >&2

# Redirect stderr to file
/do/error 2>/tmp/err.msg

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

乞讨 2024-10-24 09:29:07

使用Write-Error写入stderr。要将 stderr 重定向到文件,请使用:

 Write-Error "oops" 2> /temp/err.msg

 exe_that_writes_to_stderr.exe bogus_arg 2> /temp/err.msg

请注意,PowerShell 将错误写入错误记录。如果您想避免错误记录的详细输出,您可以自己写出错误信息,如下所示:

PS> Write-Error "oops" -ev ev 2>$null
PS> $ev[0].exception
oops

-EV-ErrorVariable 的缩写(别名)。任何错误都将存储在此参数的参数命名的变量中。 PowerShell 仍会向控制台报告错误,除非我们将错误重定向到 $null

Use Write-Error to write to stderr. To redirect stderr to file use:

 Write-Error "oops" 2> /temp/err.msg

or

 exe_that_writes_to_stderr.exe bogus_arg 2> /temp/err.msg

Note that PowerShell writes errors as error records. If you want to avoid the verbose output of the error records, you could write out the error info yourself like so:

PS> Write-Error "oops" -ev ev 2>$null
PS> $ev[0].exception
oops

-EV is short (an alias) for -ErrorVariable. Any errors will be stored in the variable named by the argument to this parameter. PowerShell will still report the error to the console unless we redirect the error to $null.

南…巷孤猫 2024-10-24 09:29:07

注意:

  • 这个答案是关于当从外部世界调用 PowerShell 脚本时从外部世界的角度写入 stderr 的内容;虽然答案是从 Windows shell cmd.exe 的角度编写的,但它同样适用于 Unix shell,例如 bash 与 PowerShell Core 结合使用。


  • 相比之下,在 Powershell 中,您应该使用 Write-Error,如 基思·希尔的回答

  • 遗憾的是,没有一种统一的方法可以同时在PowerShell内部和外部工作 -请参阅此我的回答供讨论。


添加到 @Chris Sear 的精彩答案:

虽然 $host.ui.WriteErrorLine 应该在所有主机中工作,但在通过 cmd.exe 调用时不会(默认情况下)写入 stderr ,例如来自批处理文件。
相比之下,[Console]::Error.WriteLine总是

因此,如果您想编写一个在从 cmd.exe 调用时在输出流方面表现良好的 PowerShell 脚本,请使用以下函数 Write-StdErr< /code>,它使用 [Console]::Error.WriteLine
在常规 PS / cmd.exe 主机(控制台窗口)中,以及 $host.ui.WriteErrorLine 否则:

<#
.SYNOPSIS
Writes text to stderr when running in a regular console window,
to the host''s error stream otherwise.

.DESCRIPTION
Writing to true stderr allows you to write a well-behaved CLI
as a PS script that can be invoked from a batch file, for instance.

Note that PS by default sends ALL its streams to *stdout* when invoked from
cmd.exe.

This function acts similarly to Write-Host in that it simply calls
.ToString() on its input; to get the default output format, invoke
it via a pipeline and precede with Out-String.

#>
function Write-StdErr {
  param ([PSObject] $InputObject)
  $outFunc = if ($Host.Name -eq 'ConsoleHost') {
    [Console]::Error.WriteLine
  } else {
    $host.ui.WriteErrorLine
  }
  if ($InputObject) {
    [void] $outFunc.Invoke($InputObject.ToString())
  } else {
    [string[]] $lines = @()
    $Input | % { $lines += $_.ToString() }
    [void] $outFunc.Invoke($lines -join "`r`n")
  }
}

可选背景信息:如何PowerShell CLI 的输出流可以被外部调用者看到:

在内部,PowerShell 比传统输出流(stdout 和 stderr)更多,并且它们的数量随着时间的推移而增加(尝试 Write-Warning“I '会闻所未闻。" 3> $null 作为示例,并在 Get-Help about_Redirection

与外界交互时,PowerShell 必须映射非传统输出流然而

,奇怪的是,PowerShell 默认发送其所有流(包括 Write-Host 和 $host.ui.WriteErrorLine()) 输出)到 stdout,当从 cmd.exe 调用时,即使将 PowerShell 的错误流映射到 stderr 是合乎逻辑的选择。此行为从(至少)v2 开始生效,并且从 v5.1 起仍然适用(并且由于向后兼容性的原因可能不会改变 - 请参阅 GitHub 问题 #7989)。

如果您从 cmd.exe 调用它,您可以使用以下命令验证这一点:

powershell -noprofile -command "'out'; Write-Error 'err'; Write-Warning 'warn'; Write-Verbose -Verbose 'verbose'; $DebugPreference='Continue'; write-debug 'debug'; $InformationPreference='Continue'; Write-Information 'info'; Write-Host 'host'; $host.ui.WriteErrorLine('uierr'); [Console]::Error.WriteLine('cerr')" >NUL

该命令写入所有 PowerShell 输出流(当您在 PowerShell 之前版本上运行时) v5 版本中,您将看到与 Write-Information 相关的附加错误消息,该消息是在 PowerShell v5 中引入的)并且具有 cmd.exe 重定向仅 stdout< /em> 到 NUL(即抑制 stdout 输出;>NUL)。

除了 cerr(来自 [Console]::Error.WriteLine(),直接写入 stderr)之外,您将看到没有输出 - 所有PowerShell 的流被发送到标准输出。

也许更奇怪的是,可以捕获 PowerShell 的错误流,但只能通过重定向

如果您更改 >NUL 到上面的 2>NUL,它只是 PowerShell 的错误流$host.ui.WriteErrorLine() 输出压制;当然,与任何重定向一样,您也可以将其发送到文件
(如上所述,[Console]::Error.WriteLine()]总是输出到stderr,无论后者是否被重定向。)

举一个更有针对性的例子(再次,从 cmd.exe 运行):

powershell -noprofile -command "'out'; Write-Error 'err'" 2>NUL

以上仅输出 out - Write-Error 的输出被抑制。

总结

  • 没有任何(cmd.exe)重定向或stdout重定向(< code>>... 或 1>...),PowerShell 将其所有输出流发送到stdout。< /p>

  • 通过stderr重定向(2>...),PowerShell选择性将其错误流发送到stderr(无论 stdout 是否也被重定向)。

  • 作为推论,以下常见习惯用法无法按预期工作:

    powershell ...>data-output.txt
    正如人们所期望的那样,这不会在将 stderr 输出打印到终端时仅将 stdout 发送到文件 data-output.txt ;相反,你必须使用

    powershell ... >data-output.txt 2>err-output.tmp;输入 err-output.tmp >&2;删除错误输出.tmp

由此可见,PowerShell 能够识别 cmd.exe 的重定向并有意调整其行为。
(这也可以从 PowerShell 在 cmd.exe 控制台 中生成彩色输出中看出,同时在输出重定向到文件时剥离颜色代码。 )

Note:

  • This answer is about writing to stderr from the perspective of the outside world when a PowerShell script is called from there; while the answer is written from the perspective of the Windows shell, cmd.exe, it equally applies to Unix shells such as bash when combined with PowerShell Core.

  • By contrast, from within Powershell, you should use Write-Error, as explained in Keith Hill's answer.

  • Sadly, there is no unified approach that will work from both within PowerShell and from the outside - see this answer of mine for a discussion.


To add to @Chris Sear's great answer:

While $host.ui.WriteErrorLine should work in all hosts, it doesn't (by default) write to stderr when invoked via cmd.exe, such as from a batch file.
[Console]::Error.WriteLine, by contrast, always does.

So if you want to write a PowerShell script that plays nicely in terms of output streams when invoked from cmd.exe, use the following function, Write-StdErr, which uses [Console]::Error.WriteLine
in the regular PS / cmd.exe host (console window), and $host.ui.WriteErrorLine otherwise:

<#
.SYNOPSIS
Writes text to stderr when running in a regular console window,
to the host''s error stream otherwise.

.DESCRIPTION
Writing to true stderr allows you to write a well-behaved CLI
as a PS script that can be invoked from a batch file, for instance.

Note that PS by default sends ALL its streams to *stdout* when invoked from
cmd.exe.

This function acts similarly to Write-Host in that it simply calls
.ToString() on its input; to get the default output format, invoke
it via a pipeline and precede with Out-String.

#>
function Write-StdErr {
  param ([PSObject] $InputObject)
  $outFunc = if ($Host.Name -eq 'ConsoleHost') {
    [Console]::Error.WriteLine
  } else {
    $host.ui.WriteErrorLine
  }
  if ($InputObject) {
    [void] $outFunc.Invoke($InputObject.ToString())
  } else {
    [string[]] $lines = @()
    $Input | % { $lines += $_.ToString() }
    [void] $outFunc.Invoke($lines -join "`r`n")
  }
}

Optional background information: How the PowerShell CLI's output streams are seen by outside callers:

Internally, PowerShell has more than the traditional output streams (stdout and stderr), and their count has increased over time (try Write-Warning "I'll go unheard." 3> $null as an example, and read more at Get-Help about_Redirection.

When interfacing with the outside world, PowerShell must map the non-traditional output streams to stdout and stderr.

Strangely, however, PowerShell by default sends all its streams (including Write-Host and $host.ui.WriteErrorLine() output) to stdout when invoked from cmd.exe, even though mapping PowerShell's error stream to stderr would be the logical choice. This behavior has been in effect since (at least) v2 and still applies as of v5.1 (and probably won't change for reasons of backward compatibility - see GitHub issue #7989).

You can verify this with the following command, if you invoke it from cmd.exe:

powershell -noprofile -command "'out'; Write-Error 'err'; Write-Warning 'warn'; Write-Verbose -Verbose 'verbose'; $DebugPreference='Continue'; write-debug 'debug'; $InformationPreference='Continue'; Write-Information 'info'; Write-Host 'host'; $host.ui.WriteErrorLine('uierr'); [Console]::Error.WriteLine('cerr')" >NUL

The command writes to all PowerShell output streams (when you run on a pre-PowerShell-v5 version, you'll see an additional error message relating to Write-Information, which was introduced in PowerShell v5) and has cmd.exe redirect stdout only to NUL (i.e., suppress stdout output; >NUL).

You will see no output except cerr (from [Console]::Error.WriteLine(), which writes directly to stderr) - all of PowerShell's streams were sent to stdout.

Perhaps even more strangely, it is possible to capture PowerShell's error stream, but only with a redirection:

If you change >NUL to 2>NUL above, it is exclusively PowerShell's error stream and $host.ui.WriteErrorLine() output that will be suppressed; of course, as with any redirection, you can alternatively send it to a file.
(As stated, [Console]::Error.WriteLine()] always outputs to stderr, whether the latter is redirected or not.)

To give a more focused example (again, run from cmd.exe):

powershell -noprofile -command "'out'; Write-Error 'err'" 2>NUL

The above only outputs out - Write-Error's output is suppressed.

To summarize:

  • Without any (cmd.exe) redirection or with only a stdout redirection (>... or 1>...), PowerShell sends all its output streams to stdout.

  • With a stderr redirection (2>...), PowerShell selectively sends its error stream to stderr (irrespective of whether stdout is also redirected or not).

  • As a corollary, the following common idiom does not work as expected:

    powershell ... >data-output.txt
    This will not, as one might expect, send only stdout to file data-output.txt while printing stderr output to the terminal; instead, you'd have to use

    powershell ... >data-output.txt 2>err-output.tmp; type err-output.tmp >&2; del err-output.tmp

It follows that PowerShell is aware of cmd.exe's redirections and adjusts its behavior intentionally.
(This is also evident from PowerShell producing colored output in the cmd.exe console while stripping the color codes when output is redirected to a file.)

杀手六號 2024-10-24 09:29:07

您可能想要这个:

$host.ui.WriteErrorLine('I work in any PowerShell host')

您可能还会看到以下内容,但它假设您的 PowerShell 主机是控制台
窗口/设备,所以我认为它不太有用:

[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')

You probably want this:

$host.ui.WriteErrorLine('I work in any PowerShell host')

You might also see the following, but it assumes your PowerShell host is a console
window/device, so I consider it less useful:

[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文