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

3

我可以从以下位置管道传输回来吗:

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

我希望能够获取构建的最后一行并显示进度,类似于:
$OUTPUT = $(flutter build ios --release --no-codesign | out | tail -1)

假设的out工具还会将输出发送到终端。你知道怎么做吗?


假设有一个输出命令,那么在 OSX 或 Linux 中,即使没有 $( ),这应该可以正常工作。 - js2010
1
在Bash中,$VAR=...是语法错误,赋值语句中的变量名前不应该加上美元符号(空格也可能会有问题)。 - Aaron
4个回答

2
注意:
  • On Unix-like platforms, with external-program output, js2010's elegant tee /dev/tty solution is the simplest.

  • The solutions below, which also work on Windows, may be of interest for processing external-program output line by line in PowerShell.

  • A general solution that also works with the complex objects that PowerShell-native commands can output, requires different approaches:

    • In PowerShell (Core) 7+, use the following:

      # PS v7+ only. Works on both Windows and Unix
      ... | Tee-Object ($IsWindows ? 'CON' : '/dev/tty')
      
    • In Windows PowerShell, where Tee-Object unfortunately doesn't support targeting CON, a proxy function that utilizes Out-Host is required - see this answer.


以下是一个 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] 在变量名称的左侧进行赋值时,$符号以及=周围的空格($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"

希望原帖作者能够澄清,但问题中的代码是PowerShell;虽然PowerShell本身没有tail命令,在macOS或Linux上运行PowerShell _Core_(v6+)可以使用标准的tail实用程序,即使在Windows上也有可用的tail端口。 - mklement0

1

我在管道中使用write-progress。 为了保持可读性,我编写了一个函数。

function 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(甚至是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中,它用于组合多个管道。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接