带有 Invoke-Expression 的 powershell 的 Stderr 和 stdout 没有输出或错误 [英] Stderr and stdout for powershell with Invoke-Expression has no output or errors
问题描述
我正在尝试通过运行 java 进程来获取 stdout
和 stderr
,并且看到了一种看似简单、很酷的方法,但它没有用:
I am trying to get stdout
and stderr
from running a java process, and saw what seemed like an easy, cool way to do it, but it did not work:
$command = "java -jar secretserver-jconsole.jar -s 123456 Password"
Invoke-Expression $command -OutVariable output -ErrorVariable errors
Write-Host "stdout: $output"
Write-Host "stderr: $errors"
$output
或 $errors
不显示任何内容.
Nothing displays with $output
or $errors
.
我现在正在使用:
$output = cmd /c $command
这确实为我提供了一些 stdout
,但它并不理想,因为我想要 $error
消息.
This does get me some stdout
, but it is not ideal as I want $error
message.
我什至尝试了这种精心设计的方法,但它似乎没有运行我认为的进程,因为它几乎立即返回,而且我知道正常进程任务几秒钟.它也没有显示输出或错误:
I tried even this elaborate method, but it does not even seem to run the process I think as it returns almost instantly, and I know the normal process tasks several seconds. It also shows no output or error:
$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = 'java'
$psi.Arguments = @("-jar","secretserver-jconsole.jar","-
s","123456","Password")
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
[void]$process.Start()
$output = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
Write-Host "stdout: $output"
(tried: adding:
do
$process.StandardOutput.ReadLine()
}
while (!$process.HasExited)
推荐答案
注意:下面的解决方案假设一个行为良好的外部实用程序:一个将数据发送到 stdout 和 错误消息 到 stderr.如果给定的实用程序意外地将错误消息发送到 stdout,就像 OP 的情况一样,您必须自己解析 stdout 输出以提取错误消息.
Note: The solution below assumes a well-behaved external utility: one that sends data to stdout, and error messages to stderr. If a given utility unexpectedly sends error messages to stdout instead, as appears to be the case for the OP, you must do your own parsing of stdout output to extract error messages.
$stdout = java -jar secretserver-jconsole.jar -s 123456 Password 2>($tmpFile=New-TemporaryFile)
$stderr = Get-Content $tmpFile; Remove-Item $tmpFile
New-TemporaryFile
需要 PSv5,但您可以在早期版本中使用 [io.path]::GetTempFileName()
.
New-TemporaryFile
requires PSv5, but you can use [io.path]::GetTempFileName()
in earlier versions.
请注意,$stdout
和 $stderr
都将包含一个字符串 array,每个项目代表一个输出行.
Note that both $stdout
and $stderr
will contain a string array, with each item representing an output line.
外部实用程序的退出代码反映在 PowerShell 的自动 $LASTEXITCODE
变量中.
The external utility's exit code is reflected in PowerShell's automatic $LASTEXITCODE
variable.
请注意,捕获 stdout 和 stderr 组合实际上更容易:
Note that capturing stdout and stderr combined is actually easier:
$stdoutAndStdErr = java -jar secretserver-jconsole.jar -s 123456 Password 2>&1
注意:每个 stderr 行在结果中都表示为一个 [System.Management.Automation.ErrorRecord]
实例,但它们的计算结果为 contents字符串上下文中的行.
Note: The stderr lines are each represented as a [System.Management.Automation.ErrorRecord]
instance in the result, but they evaluate to the contents of the line in a string context.
至于你尝试了什么:
通常不需要在 string 中存储命令(因此很少需要使用 Invoke-Expression
,它的使用可能有风险).
There's generally no need to store a command in a string (and therefore rarely a need to use Invoke-Expression
, whose use can be risky).
- 或者:甚至直接调用外部命令行(注意 PowerShell 可能不需要的命令行解释;在 PSv3 中,
--%
关闭 PowerShell 的解释 - 参见Get-Help about_Parsing
), - 或者,如果您需要先将命令存储在变量中,请使用脚本块 (
$cmd = { ... }
),然后再调用它使用&
(调用运算符)或.
(点源运算符) - 前者为 PS 变量创建一个子作用域,后者不会.
- Either: invoke even external command lines directly (be mindful of possibly unwanted interpretation of the command line by PowerShell; in PSv3,
--%
turns off PowerShell's interpretation - seeGet-Help about_Parsing
), - or, if you need to store the command in a variable first, use a script block (
$cmd = { ... }
), and invoke it later with&
(call operator) or.
(dot-sourcing operator) - the former creates a child scope for PS variables, the latter does not.
-OutVariable
和 -ErrorVariable
公共参数仅设计用于 PowerShell 的 输出流,而不是外部世界的 stdout 和 stderr.
The -OutVariable
and -ErrorVariable
common parameters are only designed to work with PowerShell's output streams, not the outside world's stdout and stderr.
PowerShell 捕获 stdout 输出,就好像它已发送到 PowerShell 的成功输出流一样,并将输出行视为字符串数组.
Stderr 输出通过(并且不会反映在 $Error
中),但您可以将其重定向到带有 2>$file
的文件,或您可以使用 2>&1
将其合并到成功流中(在这种情况下,每个 stderr 行都表示为一个 [System.Management.Automation.ErrorRecord]
实例).
Stderr output is passed through (and is not reflected in $Error
), but you can redirect it to a file with 2>$file
, or you can merge it into the success stream with 2>&1
(in which case the stderr lines are each represented as a [System.Management.Automation.ErrorRecord]
instance).
这篇关于带有 Invoke-Expression 的 powershell 的 Stderr 和 stdout 没有输出或错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!