PowerShell:捕获在变量中写入stderr的外部进程的输出

PowerShell:捕获在变量中写入stderr的外部进程的输出,powershell,powershell-2.0,Powershell,Powershell 2.0,我需要将外部进程的输出捕获到一个变量(字符串)中,以便对此进行一些处理 只要进程写入stdout,来自的答案就可以很好地工作。但是,如果进程失败,它将写入stderr。我也想捕捉这个字符串,但我不知道怎么做 例如: $cmdOutput = (svn info) | out-string 这是可行的,除非SVN有错误。如果发生错误,SVN将写入stderr,$cmdOutput为空 如何在PowerShell的变量中捕获写入stderr的文本 试试这个: $cmdOutput = svn in

我需要将外部进程的输出捕获到一个变量(字符串)中,以便对此进行一些处理

只要进程写入stdout,来自的答案就可以很好地工作。但是,如果进程失败,它将写入stderr。我也想捕捉这个字符串,但我不知道怎么做

例如:

$cmdOutput = (svn info) | out-string
这是可行的,除非SVN有错误。如果发生错误,SVN将写入stderr,
$cmdOutput
为空

如何在PowerShell的变量中捕获写入stderr的文本

试试这个:

$cmdOutput = svn info 2>&1
以概述作为补充:

要简要解释重定向表达式
2>&1

2>
将(
)PowerShell的错误输出流(其编号为
2
(并映射到stderr)重定向到(
&
)PowerShell的成功输出流,其编号为
1
(并映射到stdout)。
跑去了解更多

将stdout和stderr输出合并为一个合并流:
作为字符串形式的输出行集合,无法分辨哪一行来自哪个流:

使用平台本机shell在源代码处执行合并使PowerShell只能看到stdout输出,与往常一样,stdout输出收集在字符串数组中

在以下示例中,每个命令都创建stdout和stderr输出。
为了方便和简洁,所有命令都使用PSv3+语法

Windows示例:

Unix示例(PowerShell核心):

注:

  • 您确实需要显式地调用平台本机shell(
    cmd/c
    在Windows上,而
    sh-c
    在Unix上),这会降低这种方法的可移植性

  • 您将无法从生成的行数组中分辨出哪一行来自哪个流。
    请参见下文,了解如何进行区分


作为字符串行(来自stdout)和
[System.Management.Automation.ErrorRecord]
“行”(来自stderr):

通过使用PowerShell的
2>&1
重定向,您还可以获得表示合并的stdout和stderr流的单个行集合,但stderr行不是作为字符串捕获的,而是作为
[System.Management.Automation.ErrorRecord]
实例捕获的

警告:自Windows PowerShell v5.1/PowerShell Core v6.0.0-beta.4起,当您在
$ErrorActionPreference='Stop'
生效时,使用
2>
重定向PowerShell的错误流时,出现了一个错误-请参阅

通过检查每个数组元素的数据类型,您可以灵活地区分标准输出和标准输出行。
另一方面,您可能需要将stderr行转换为字符串

在PSv6中,仅输出捕获的输出时,不同的数据类型并不明显,但可以通过反射来判断:

# Let PowerShell merge the streams with 2>&1, which captures
# stdout lines as strings and stderr lines as [System.Management.Automation.ErrorRecord] 
# instances.
$allOutput = cmd /c ver '&' dir \nosuch 2>&1
检查结果:

PS> $allOutput | % GetType | % Name
String
String
String
String
String
String
ErrorRecord
如您所见,最后一个数组元素是一个错误记录,它表示由
dir\nosuch
命令生成的单个
文件未找到
stderr输出行

注意:在PSv5.1之前,当您将捕获的输出输出输出到控制台时,
[System.Management.Automation.ErrorRecord]
实例实际以与PowerShell错误相同的格式呈现,可能使其看起来好像当时发生了错误。
在PSv6中,这些错误记录只打印它们的消息,即原始stderr行的内容,从视觉上看,您无法判断打印的是错误记录,而不是字符串

要将所有捕获的输出转换为字符串,请执行以下操作:

$allOutput = cmd /c ver '&' dir \nosuch 2>&1 | % ToString
要过滤掉stderr行(并在此过程中将其转换为字符串),请执行以下操作:


单独捕获stderr输出:
使用临时文件

$allOutput = cmd /c ver '&' dir \nosuch 2>&1 | % ToString
从PSv5.1开始,单独捕获stderr输出的唯一直接方法是使用重定向
2>
和文件名目标;i、 例如,要捕获文件中的stderr输出(作为文本):

显然,这很麻烦,而且比内存中的操作要慢


使用PSv4+
.Where()
收集运算符

$allOutput = cmd /c ver '&' dir \nosuch 2>&1 | % ToString
(鲜为人知的)PSv4+
.Where()
集合运算符允许您根据元素是否通过布尔测试将集合一分为二:

 # Merge the streams first, so they go to the success stream, then
 # split the objects in the merged stream by type.
 $stdoutOutput, $stderrOutput = (cmd /c ver '&' dir \nosuch 2>&1).Where({
   $_ -isnot [System.Management.Automation.ErrorRecord]
 }, 'Split')

 # Convert the collected [System.Management.Automation.ErrorRecord]
 # instances to strings.
 $stderrOutput = $stderrOutput | % ToString

未来可能的替代方案:

提出了一种新的重定向语法,允许更简单地在变量中收集stderr行:

 # As of v5.1: WISHFUL THINKING
 $stdout = cmd /c ver '&' dir \nosuch 2>&stderr # collect stderr lines in var. $stderr

这很有效。你能解释一下为什么(语法是什么意思)?@driis 1是标准输出描述符,2是错误输出。使用2>&1,我们将错误重定向到标准输出。如果它有效,你应该接受它作为答案。甚至在你的另一个问题,你已经链接。
 # Merge the streams first, so they go to the success stream, then
 # split the objects in the merged stream by type.
 $stdoutOutput, $stderrOutput = (cmd /c ver '&' dir \nosuch 2>&1).Where({
   $_ -isnot [System.Management.Automation.ErrorRecord]
 }, 'Split')

 # Convert the collected [System.Management.Automation.ErrorRecord]
 # instances to strings.
 $stderrOutput = $stderrOutput | % ToString
 # As of v5.1: WISHFUL THINKING
 $stdout = cmd /c ver '&' dir \nosuch 2>&stderr # collect stderr lines in var. $stderr