Как одновременно захватить вывод внешней команды и распечатать ее на терминал - PullRequest
2 голосов
/ 29 января 2020

Могу ли я вернуться с:

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

Я хотел бы получить обе последние строки из сборки и показать прогресс, что-то вроде

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

, где гипотетический out утилита также отправит вывод на терминал.

Знаете ли вы, как?

Ответы [ 4 ]

1 голос
/ 29 января 2020

Я считаю, что это будет работать, по крайней мере, в osx или linux powershell (или даже Windows Подсистеме для Linux), в которых доступны эти команды. Я проверил это с «ls» вместо «трепетание». Есть ли на самом деле команда "out"?

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

Или, если предположить, что tee не привязан к объекту tee. На самом деле, tee-object тоже будет работать.

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

Он также будет работать с $ (), но вам это не нужно. В powershell он используется для объединения нескольких конвейеров.

1 голос
/ 29 января 2020

Примечание: На Unix -подобных платформах элегантное решение tee /dev/tty js2010 *1002* является самым простым; Помимо работы над Windows, приведенные ниже решения могут представлять интерес для построчной обработки вывода внешней программы в PowerShell.


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.

Если сообщения о ходе выполнения go - 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-подобных оболочках.

1 голос
/ 29 января 2020

Я использую write-progress в конвейере. Чтобы сохранить читабельный конвейер, я написал функцию

, функция Write-PipedProgress {<# </p>

.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 голос
/ 29 января 2020

Полагаю, вы имеете в виду 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"
...