通常,我知道如何将命令的输出捕获到Powershell中的变量中:
> $output = python3 --version
> Write-Host $output
Python 3.7.0
Python 3打印其版本,但已捕获到变量$output
中,并且控制台上未显示任何内容。如预期:
> $output = python3 --version
> Write-Host $output
Python 3.7.0
但是对于Python 2,它不起作用。 Python 2会打印其版本,但会在控制台上显示而不是捕获,并且变量$output
为空。
> $output = python2 --version
Python 2.7.15
> Write-Host $output
>
我尝试了一些其他语法,但到目前为止没有任何帮助:
> $output = (python2 --version) # use a subcommand
Python 2.7.15
> $output = "$(python2 --version)" # enclose the subcommand into a string
Python 2.7.15
如果我在Write-Command
中使用它,输出将如下所示:
> Write-Host "Python version: $(python2 --version)"
Python 2.7.15
Python version:
>
Python 2如何打印其未被捕获到变量中的版本,并且有可能以任何方式捕获它?
答案 0 :(得分:3)
这是由 Python 2导致的,该版本将版本打印到stderr
而不是stdout
。程序调用输出的分配仅捕获stdout
,在这种情况下为空。另一方面,默认情况下将stderr
打印到控制台,这就是$output
变量为空并且版本被打印到控制台的原因。有关详情,请参见下文。
tl;医生:
# Redirect stderr to the success output stream and convert to a string.
$output = (python --version 2>&1).ToString()
# $? is now $True if python could be invoked, and $False otherwise
对于可能返回多条 stderr行的命令,请使用:
PSv4 +,使用.ForEach()
方法:
$output = (python --version 2>&1).ForEach('ToString')
PSv3-,使用ForEach-Object
cmdlet (其内置别名为%
):
# Note: The (...) around the python call are required for
# $? to have the expected value.
$output = (python --version 2>&1) | % { $_.ToString() }
# Shorter PSv3+ equivalent, using an operation statement
$output = (python --version 2>&1) | % ToString
正如Mathias R. Jessen在对问题的评论中指出的那样,您自己根据版本进行了说明, python
2.x -令人惊讶的是-输出它的版本信息是 stderr 而不是stdout,与 3.x 不同。
您无法使用$output = ...
捕获输出的原因是将外部程序调用的输出分配给变量只能捕获其 stdout 输出。
主要解决方法是使用重定向2>&1
合并PowerShell的错误流(如果将Powerder的类似物重定向到stderr,则将stderr输出映射到 >)到PowerShell的成功输出流(标准输出模拟)中,然后将其捕获到变量中。
但是,这有两个副作用:
由于2>&1
重定向现在会涉及PowerShell的错误流(默认情况下,stderr输出会传递到控制台),所以 {{1} }始终设置为$?
,因为将任何内容写入错误流都可以做到这一点(即使最终将错误流发送到其他地方,在这种情况下)。
请注意,在没有重定向的情况下,$False
未设置为$?
(除了ISE中的{{3 }}),因为stderr输出将永远不会“接触” PowerShell的错误输出流。
在PowerShell控制台中,调用没有进行$False
重定向的外部程序时,如果{em> exit退出,则2>
设置为$?
仅 代码是非零($False
)。
因此,使用$LASTEXITCODE -ne 0
解决了一个问题(无法捕获输出),同时引入了另一个问题(2>&1
错误地设置为$?
)-有关补救措施,请参见下文。
不是字符串写入成功输出流,而是$False
实例,因为PowerShell将每条stderr输出行都包装在其中一个。
如果仅在 string 上下文中使用这些实例,例如[System.Management.Automation.ErrorRecord]
,则可能不会注意到或不在意。
"Version: $output"
(对于单条输出线)和.ToString()
/ .ForEach('ToString')
(对于多条输出线)可消除两种副作用:
它们将(...) | % ToString
实例转换回字符串。
他们将[System.Management.Automation.ErrorRecord]
重置为$?
,因为$True
/ .ToString()
调用/在命令周围使用.ForEach()
是表达式,即使它们包含将自身设置为(...)
到$?
的命令,它们也被认为是成功的。
注意:
如果找不到可执行文件$False
,PowerShell本身将引发语句终止错误,这意味着对python
的赋值将被跳过( (其值(如果存在)将不会更改),默认情况下,您会收到嘈杂的错误输出,并且$output
将设置为$?
。
如果可以调用$False
并且它报告错误(对于python
则不太可能),如非零所示退出代码,您可以通过自动--version
变量检查退出代码(其值在下次调用外部程序之前不会更改)。< / p>
利用$LASTEXITCODE
到命令周围这样简单的操作使(...)
总是返回$?
(除非发生语句或脚本终止错误),在上述方法中,但通常是模糊的行为,可能被认为是有问题的-请参见an unfortunate discrepancy。