有没有一种方法可以设置一个变量,将输出放在stdout或null中



我想在代码中设置一个变量,该变量将最终定义我是否会看到一些输出。

  • "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-HostWrite-Outputcmdlet一样,还有一些其他cmdlet控制要写入哪个流

关于输出流

总共有6个流。记下它们的编号,因为这些流标识符用于控制重定向哪些流:

  • 1-成功流-此流用于沿Powershell管道传递信息。这就是";默认";流,但也可以用Write-Output写入
  • 2-错误流-应将错误写入此流。可以用Write-Error写入,并附带进一步的错误信息
  • 3-警告流-用于写入警告信息。可以使用
    Write-Warning写入
  • 4-详细流-用于写入详细输出。默认情况下不显示,但可以通过设置$VerbosePreference = "Continue"或在函数或脚本上使用[CmdletBinding()]属性并传入-Verbose标志来进行显示。使用Write-Verbose写入详细流
  • 5-调试流-用于写入调试流,并可选择触发断点。默认情况下不显示或触发断点,但可以使用$DebugPreference变量进行控制,也可以使用脚本或函数上的[CmdletBinding()]属性和-Debug标志进行控制。可以使用
    Write-Debugcmdlet写入调试流
  • 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-Objectcmdlet将输出流重定向到文件和管道。这也适用于变量:

$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写入VerboseDebug流,您仍然可以将输出重定向到$null或使用Out-Nullcmdlet。回想一下这个答案顶部的编号流,它们将在这里被引用:

使用重定向

# 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-Defaultcmdlet(您应该never直接调用
Out-Default)在成功流上发送所有未分配的输出。也就是说,Out-Host的一个有用调用是将格式化的对象数据同步输出到控制台:

注意:您可以重定向其他输出流中的信息,也可以将其输出到Out-Host,但没有理由这样做。对象数据在成功流上只会保持不变,其他流在重定向之前会先将对象转换为其ToString()表示。这也是为什么在这种情况下将对象管道化到Out-HostWrite-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-Outputcmdlet,尤其是学习如何使用Write-WarningWrite-VerboseWrite-ErrorWrite-Debugcmdlet。

好的。感谢这里所有的智囊团给了我们动力。这个答案可能不是最好的方法,但它有效

要做到这一点,你需要了解两件事:

  1. 如果你习惯于使用Write-Host,它将不起作用,你将不得不使用Write-Output
  2. 您可能需要学习使用脚本块作为函数参数

一个是不言自明的,所以下面是如何获得#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" }

最后,这里是我的输出和代码的一个例子

相关内容

  • 没有找到相关文章

最新更新