如何同时捕获外部命令输出并将其打印到终端

问题描述 投票:0回答:4

我可以从以下地方回传:

$OUTPUT = $(flutter build ios --release --no-codesign | tail -1)

我想从构建中获取最后一行并显示进度,例如

$OUTPUT = $(flutter build ios --release --no-codesign | out | tail -1)

假设的

out
实用程序也会将输出发送到终端。

你知道怎么做吗?

powershell terminal tee
4个回答
2
投票

注:

  • Unix类平台上,具有外部程序输出js2010优雅的

    tee /dev/tty
    解决方案是最简单的。

  • 下面的解决方案也适用于Windows,可能对在PowerShell中处理外部程序逐行输出感兴趣。

  • 通用解决方案也适用于PowerShell本机命令可以输出的复杂对象需要不同的方法

    • PowerShell (Core) 7+ 中,使用以下命令:

      # PS v7+ only. Works on both Windows and Unix
      ... | Tee-Object ($IsWindows ? '\\.\CON' : '/dev/tty')
      
    • Windows PowerShell 中,不幸的是,

      Tee-Object
      不支持定位
      CON
      ,需要使用 Out-Host
      代理功能
      - 请参阅此答案


A PowerShell 解决方案(假设您问题中的代码是 PowerShell[1]):

我不确定

flutter
如何报告其进度,但以下方法可能有效:

如果一切都进入stdout

$OUTPUT = flutter build ios --release --no-codesign | % {
  Write-Host $_ # print to host (console)
  $_  # send through pipeline
} | select -Last 1

注意:

%
ForEach-Object
的内置别名,
select
Select-Object
的别名。

如果进度消息转到 stderr:

$OUTPUT = flutter build ios --release --no-codesign 2>&1 | % {
  Write-Host $_.ToString() # print to host (console)
  if ($_ -is [string]) { $_ }  # send only stdout through pipeline
} | select -Last 1

[1] 正如变量名

 赋值的 LHS 
中的 $ 印记以及
=

周围的空格所证明的那样 (
$OUTPUT = 
),这两种方法都无法在
bash
/类似 POSIX 的 shell 中按预期工作。


1
投票

我认为你的意思是 bash 因为据我所知,powershell 中没有

tail

以下是如何查看命令的输出,同时仍将其捕获到变量中。

#!/bin/bash

# redirect the file descriptor 3 to 1 (stdout)
exec 3>&1

longRunningCmd="flutter build ios --release --no-codesign"

# use tee to copy the command's output to file descriptor 3 (stdout) while 
# capturing 1 (stdout) into a variable
output=$(eval "$longRunningCmd" | tee >(cat - >&3) )

# last line of output
lastline=$(printf "%s" "$output" | tail -n 1)

echo "$lastline"

1
投票

我在管道中使用写入进度。 为了保持可读的管道,我写了一个函数

函数 Write-PipedProgress{ <#

.SYNOPSIS
    Insert this function in a pipeline to display progress bar to user

.EXAMPLE
    $Result = (Get-250Items | 
        Write-PipedProgress -PropertyName Name -Activity "Audit services" -ExpectedCount 250 |
        Process-ItemFurther)

>

[cmdletBinding()]
param(
    [parameter(Mandatory=$true,ValueFromPipeline=$true)]
    $Data,
    [string]$PropertyName=$null,
    [string]$Activity,
    [int]$ExpectedCount=100
    )

begin {
    Write-Verbose "Starting $($MyInvocation.MyCommand)"
    $ItemCounter = 0
}
process {
    Write-Verbose "Start processing of $($MyInvocation.MyCommand)($Data)"

    try {
        $ItemCounter++
        # (3) mitigate unexpected additional input volume"
        if ($ItemCounter -lt $ExpectedCount) {
            $StatusProperty = if ($propertyName) { $Data.$PropertyName } > > else { ""}
            $StatusMessage = "Processing $ItemCounter th $StatusProperty"
            $statusPercent = 100 * $ItemCounter / $ExpectedCount
            Write-Progress -Activity $Activity -Status $StatusMessage -> > PercentComplete $statusPercent
        } else {
            Write-Progress -Activity $Activity -Status "taking longer than expected" -PercentComplete 99
        }

        # return input data to next element in pipe
        $Data
    
    } catch {
        throw
    }
    finally {
        Write-Verbose "Complete processing of $Data in > $($MyInvocation.MyCommand)"
    }

}
end {
    Write-Progress -Activity $Activity -Completed
    Write-Verbose "Complete $($MyInvocation.MyCommand) - processed $ItemCounter items"
}

}

希望这有帮助;-)


1
投票

我相信这会起作用,至少在有这些命令可用的 osx 或 linux powershell(甚至是适用于 Linux 的 Windows 子系统)中。我用“ls”而不是“flutter”对其进行了测试。真的有“out”命令吗?

$OUTPUT = bash -c 'flutter build ios --release --no-codesign | tee /dev/tty | tail -1'

或者,假设 tee 没有别名为 tee-object。事实上,tee-object 也可以工作。

$OUTPUT = flutter build ios --release --no-codesign | tee /dev/tty | tail -1

它也可以与 $( ) 一起使用,但你不需要它。在powershell中,它用于组合多个管道。

© www.soinside.com 2019 - 2024. All rights reserved.