您可以将 Tee-Object 重定向到标准输出吗?

Sle*_*led 4 terminal powershell tee windows-console

我正在编写一个脚本,我想传递这些值,但也想看到它们显示

Get-Content data.txt | Tee-Object | data_processor.exe
Run Code Online (Sandbox Code Playgroud)

Tee-Object总是请求一个文件,我只想在屏幕上看到它。

mkl*_*nt0 9

为了补充zett42 的有用答案

如果您运行的是PowerShell (Core) 7+,您可以将表示终端(控制台)的文件路径传递给(位置隐含的)-FilePath参数(在Windows PowerShell中,这会导致错误,不幸的是 - 请参阅底部部分):

# PowerShell 7+ only

# Windows
Get-Content data.txt | Tee-Object \\.\CON | data_processor.exe

# Unix-like platforms (Linux, macOS)
Get-Content data.txt | Tee-Object /dev/tty | data_processor.exe

# Platform-agnostic
# See coming future improvement below (-Host)
Get-Content data.txt | Tee-Object ($IsWindows ? '\\.\CON': '/dev/tty') | data_processor.exe
Run Code Online (Sandbox Code Playgroud)

笔记:

  • GitHub 问题 #19827是一个绿灯,但迄今为止(从 PowerShell (Core) 7.3.x 开始)尚未实现的改进,将允许简化
    ($IsWindows ? '\\.\CON': '/dev/tty')-Host.

会传递所有数据,同时还将其打印到终端(控制台),像往常一样,在可用时进行丰富的格式化- 与该Tee-Object -Variable方法不同,该方法需要首先收集内存中的所有输出(这在输出方面都是一个问题)时间和内存消耗)。


Windows PowerShell解决方案:自定义代理(包装器)函数 Tee-Host进行包装Out-Host,同时传递其输入;使用它代替Tee-Object

function Tee-Host {  
  [CmdletBinding()]
  param(
    [Parameter(ValueFromPipeline)] $InputObject
  )

  begin
  {
    $scriptCmd = { Out-Host }
    $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
    $steppablePipeline.Begin($PSCmdlet)
  }
  
  process
  {
    # Pass to Out-Host, and therefore to the host (terminal)
    $steppablePipeline.Process($InputObject)
    # Pass through (to the success stream)
    $InputObject 
  }
  
  end
  {
    $steppablePipeline.End()
  }
    
}
Run Code Online (Sandbox Code Playgroud)
  • 实际上,Tee-Host其行为类似于PowerShell 7+ 中的Tee-Object \\.\CON/ ,也可以工作。Tee-Object /dev/ttyTee-Host

  • 即使在 PowerShell 7+ 中也Tee-Host可能更可取,因为它无条件地使用彩色输出,而/的着色行为取决于Tee-Object \\.\CONTee-Object /dev/tty$PSStyle.OutputRendering

它使用具有可步进管道包装的代理函数Out-Host,确保到主机格式化的输出看起来与输入直接发送到主机时相同。


zet*_*t42 8

您可以输出到变量而不是文件:

Get-Content data.txt | Tee-Object -Variable data | data_processor.exe
$data  # Output
Run Code Online (Sandbox Code Playgroud)

这会将内容传递给“data_processor.exe”并将其存储在变量中$data。仅当 .exe 完成后才会显示数据。

用于在每行发送到 .exe 之前ForEach-Object检查输出:Get-Content

Get-Content data.txt | ForEach-Object {
    Write-Host $_   # Output line to console
    $_              # Forward line to next command in chain 
} | data_processor.exe
Run Code Online (Sandbox Code Playgroud)

通过编写一个小的过滤器函数,可以使该模式更加简洁和可重用:

Filter Write-HostAndForward {
    Write-Host $_   # Output line to console
    $_              # Forward line to next command in chain    
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以写:

Get-Content data.txt | Write-HostAndForward | data_processor.exe
Run Code Online (Sandbox Code Playgroud)

评论:

虽然Write-HostAndForward适用于简单输入,例如从 接收的字符串Get-Content,但对于复杂对象,它通常不会产生与我们通常在控制台中看到的相同的输出。这是因为Write-Host只需使用该方法将输入转换为字符串.ToString(),从而跳过 PowerShell 丰富的格式系统。

您可能会想简单地替换Write-HostOut-Host,但正如mklement0所解释的那样,它将单独格式化输入对象,这将为表格式输出的每个对象生成一个标头。为了避免这种情况,mklement0 的答案显示了生成预期格式化输出的不同方法。