我想在代码中设置一个变量,该变量将最终定义我是否会看到一些输出。
"hello"
写入stdout"hello" > $null
抑制输出
我的想法是这样的:
$debugOutputSwitch = $true
$outputVar = $null
if ($debugOutputSwitch){ $outputVar = **STDOUT** }
...
Write-Host "Something I want out anyway"
"Something I might not want on STDOUT" > $outputVar
如果这个总体想法是可行的,那么STDOUT
就是我想要的
如果这个想法是完全错误的。。。好那么我失去了
您想要了解的是Powershell中的输出流和重定向。这包括关于所有不同输出流的信息,以及如何使用内置结构来控制它们的相关性。就像有Write-Host
和Write-Output
cmdlet一样,还有一些其他cmdlet控制要写入哪个流
关于输出流
总共有6个流。记下它们的编号,因为这些流标识符用于控制重定向哪些流:
-
1-成功流-此流用于沿Powershell管道传递信息。这就是";默认";流,但也可以用
Write-Output
写入 -
2-错误流-应将错误写入此流。可以用
Write-Error
写入,并附带进一步的错误信息 -
3-警告流-用于写入警告信息。可以使用
Write-Warning
写入 -
4-详细流-用于写入详细输出。默认情况下不显示,但可以通过设置
$VerbosePreference = "Continue"
或在函数或脚本上使用[CmdletBinding()]
属性并传入-Verbose
标志来进行显示。使用Write-Verbose
写入详细流 -
5-调试流-用于写入调试流,并可选择触发断点。默认情况下不显示或触发断点,但可以使用
$DebugPreference
变量进行控制,也可以使用脚本或函数上的[CmdletBinding()]
属性和-Debug
标志进行控制。可以使用Write-Debug
cmdlet写入调试流 -
6-信息流-可由
Write-Host
写入。这是控制台主机输出,不是管道的一部分
重定向流
您也可以使用重定向运算符将其他流重定向到成功流。上面的每个流都有一个与之相关的数字。这是每个流的数字表示。
重定向运算符如下:
>
-将成功流重定向到文件(覆盖)#>
-将#
流重定向到文件(例如2> somefile.txt
)>>
-将成功流重定向到文件(附加,您也可以使用带编号的流作为覆盖文件操作符)>&1
-将任何流重定向到成功流(请注意,与其他重定向运算符不同,您只能将重定向到成功流。使用其他流标识符将导致错误)
还请注意,您可以使用*
来代替流编号,它将同时重定向所有流。
以下是将输出从一个流重定向到另一个流的一些示例(如果您熟悉它,它有点UNIX-y):
# Write success stream to file
Write-Output "Here is some text for a file" > .somefile.txt
# Write error stream to file (you have to first
Write-Error "Some error occurred" 2> .somefile.txt
# Redirect all error output to the success stream
$myErrorOutput = Write-Error "My error output" 2>&1
# Append all script output streams to a single file
Get-OutputFromAllStreams.ps1 *>> somefile.txt
同时输出到文件和管道
也可以使用Tee-Object
cmdlet将输出流重定向到文件和管道。这也适用于变量:
$myString = "My Output" | Tee-Object -FilePath .somefile.txt
$myString2 = "My Output 2" | Tee-Object -Variable varName
示例函数,显示如何使用不同的Write-
cmdlet
请注意以下函数是如何使用[CmdletBinding()]
属性进行修饰的。这是使-Verbose
和-Debug
交换机工作的关键,而无需您自己定义它们。
function Write-DifferentOutputs {
[CmdletBinding()]
# These all visible by default but only the output stream is passed down the pipeline
Write-Output "Output stream"
Write-Warning "Warning stream"
Write-Error "Error stream"
Write-Host "Information stream"
# These are not visible by default, but are written when the `-Verbose` or `-Debug` flags are passed
# You can also manually set the $VerbosePreference or $DebugPreference variables to control this without parameters
Write-Verbose "Verbose stream"
Write-Debug "Debug stream"
}
使用-Verbose
或-Debug
开关调用上述函数,查看行为有何不同,也可以不使用任何标志来调用它。
如果确实需要,将输出重定向到$null
如果有您永远不想看到的输出,或者由于其他原因,无法使用Write-
cmdlet写入Verbose
或Debug
流,您仍然可以将输出重定向到$null
或使用Out-Null
cmdlet。回想一下这个答案顶部的编号流,它们将在这里被引用:
使用重定向
# Don't forget that *> redirects ALL streams, and may be what you want
Write-Output 'Success Stream' > $null
Write-Error 'Error Stream' 2> $null
Write-Warning 'Warning Stream' 3> $null
Write-Verbose 'Verbose Stream' 4> $null
Write-Debug 'Debug Stream' 5> $null
Write-Host 'Information Stream (yes you can suppress/redirect me)' 6> $null
您还可以根据命令重定向目标流:以下示例(使用早期的Write-DifferentOutputs
函数)重定向除错误和成功流的之外的所有流:
注意:您不仅限于将目标流重定向到
$null
。
Write-DifferentOutputs 6>$null 5>$null 4>$null 3>$null
使用Out-Null
记住,您可以通过将输出重定向到&1
来将其他流重定向到成功流。
# Remember, to pass information on the pipeline
# it MUST be on the success stream first
# Don't forget that *> redirects ALL streams, and may be what you want
Write-Output 'Success Stream' | Out-Null
Write-Error 'Error Stream' 2>&1 | Out-Null
Write-Warning 'Warning Stream' 3>&1 | Out-Null
Write-Verbose 'Verbose Stream' 4>&1 | Out-Null
Write-Debug 'Debug Stream' 5>&1 | Out-Null
Write-Host 'Information Stream (yes you can suppress/redirect me)' 6>&1 | Out-Null
当使用CCD_ 42是合适的("Don't Cross the Streams")时
警告:与
Write-Host
不同,Out-Host
不会输出到信息流。相反,它直接输出到主机控制台。这使得直接写入Out-Host
的任何内容都无法重定向,除非使用Start-Transcript
或使用自定义PowerShell主机。请注意,写入控制台主机的信息对于可能正在监视PowerShell输出的外部应用程序仍然可见,因为最终甚至Out-Host
输出也会到达STDOUT。
称自己为Out-Host
通常是多余的。默认情况下,PowerShell通过Out-Default
cmdlet(您应该never直接调用Out-Default
)在成功流上发送所有未分配的输出。也就是说,Out-Host
的一个有用调用是将格式化的对象数据同步输出到控制台:
注意:您可以重定向其他输出流中的信息,也可以将其输出到
Out-Host
,但没有理由这样做。对象数据在成功流上只会保持不变,其他流在重定向之前会先将对象转换为其ToString()
表示。这也是为什么在这种情况下将对象管道化到Out-Host
比Write-Host
更可取的原因。
Get-Process msedge | Out-Host
不同输出流的一个注意事项是流之间没有同步性通常这不是问题,因为PowerShell按顺序逐行执行指令,除Write-Output
成功流外,其他流也不是问题。但是,许多类型都有一个computedfor display属性,该属性是在信息发送到Out-Default
之前从脚本执行异步计算的。
这可能导致显示的对象数据与写入控制台主机的其他输出流混合。在某些情况下,这甚至可能导致写入控制台的信息丢失"跨过溪流";,如果愿意的话,因为它与渲染输出的外观有关。
考虑以下示例和输出。这并没有显示混合的流,但考虑一下如果Write-Host "end `n"
写在表的中间,那么在外部解析输出时会遇到的麻烦:
Write-Host "start `n"
Get-LocalUser
Write-Host "end `n"
输出:
start
end
Name Enabled Description
---- ------- -----------
Administrator True
DefaultAccount False A user account managed by the system.
Disabled False Built-in account for guest access to the computer/domain
特别是,这对于定义表格式的类型来说是有问题的,在将格式化的数据发送到Out-Host
进行显示之前,必须计算列宽。预先定义表宽度或根本不将输出格式化为表的类型不存在此问题。Out-Default
计算列宽最多需要300ms。
然而,当Out-Host
作为管道的一部分被显式调用时,由于对象数据从未到达Out-Default
,因此会跳过这些对象的表宽度计算。这主要用于确保要写入控制台的对象数据以正确的顺序执行。不利的一面是,表列可能不够宽,无法容纳每行中的所有数据。
总之,如果必须处理脚本的控制台输出,建议将要处理的数据格式化为字符串,并使用Write-Host
,或者使用其他方法将数据获取到适合外部处理的位置。for-display
格式不适用于外部处理。
@如果您想了解更多关于这个问题的信息,mklement1的答案将进一步深入到这个问题的细节中。
将整个命令输出重定向到Write-
cmdlet
您可以轻松地将命令或cmdlet的所有输出通过管道传输到其中一个Write-
cmdlet。我将在下面的示例中使用前面提供的Write-DifferentOutputs
,但这将适用于您运行的任何cmdlet、脚本或命令:
Write-DifferentOutputs *>&1 | Write-Verbose
上面所做的只是显示命令输出if$VerbosePreference = $Continue
,或者如果您将-Verbose
作为参数传递给脚本或函数。
总结
在你最初的问题中,你试图重新发明一个Powershell已经很好地支持的轮子。我建议您学习如何为每个流使用不同的Write-Output
cmdlet,尤其是学习如何使用Write-Warning
、Write-Verbose
、Write-Error
和Write-Debug
cmdlet。
好的。感谢这里所有的智囊团给了我们动力。这个答案可能不是最好的方法,但它有效
要做到这一点,你需要了解两件事:
- 如果你习惯于使用
Write-Host
,它将不起作用,你将不得不使用Write-Output
- 您可能需要学习使用脚本块作为函数参数
一个是不言自明的,所以下面是如何获得#2:
Function Test-SctiptBlockParam {
Param(
$scriptblock
)
if ($debugOutput) {
Invoke-Command $scriptblock
} else {
(Invoke-Command $scriptblock) > $null
}
}
Test-SctiptBlockParam -scriptblock { Write-Output "I want to see on the STDOUT sometimes" }
最后,这里是我的输出和代码的一个例子