Как сохранить новые строки из вывода команды, распечатанные с помощью Write-Host в Powershell?

Недавно (2-3 дня назад) я начал использовать Powershell. У меня есть приложение на C++, которое использует argparse для обработки некоторых аргументов командной строки. Если что-то не так, как ожидалось, мой код завершается со строкой справки, предоставленной флагом -/--help любого приложения, использующего эту библиотеку.

Я использую (вывод $PSVersionTable):

Name                           Value
----                           -----
PSVersion                      5.1.19041.2364
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.2364
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

У меня есть файл конфигурации CMake

Write-Host "${APP_NAME} (${BUILD_TYPE})"

$model = ""
$data_in = ""

Write-Host "Checking input arguments"
if ($args.count -ne 5)
{
    Write-Host "Found {0} arguments but expecting 5" -f $args.count
    Write-Host $(./pytorch_load_model.exe --help) -foregroundcolor Cyan
    exit
}

for ( $i = 0; $i -lt $args.count; $i++ ) {
    if (($args[ $i ] -eq "-m") -or ($args[ $i ] -eq "--model")){ $model=$args[ $i+1 ]}
    if (($args[ $i ] -eq "-i") -or ($args[ $i ] -eq "--input")){ $data_in=$args[ $i+1 ]}
}

$fail = $false
if ($model -eq "")
{
    Write-Host "No path for model provided"
}
if ($data_in -eq "")
{
    Write-Host "No path for input provided"
}
if ($fail -eq $true)
{
    Write-Host (./model.exe --help)
    exit
}

# TODO Add check if $opencv and $libtorch valid dir paths
$opencv = "${OPENCV_BIN}"
$libtorch = "${LIBTORCH_BIN}"
#$model = "${PTH_MODEL_PATH}"
#$input = "${INPUT_IMG_PATH}"
Write-Host "Executing model"
$env:Path = "$($env:Path);$($opencv);$($libtorch)"; ./pytorch_load_model.exe -m "$($model)" -i "$($data_in)"

который обрабатывается с помощью configure_file() для вывода скрипта (*.ps1 файла), который добавляется в двоичный каталог моего проекта (EXE, dlls и другие данные, относящиеся к времени выполнения). Он настраивает PATH так, что приложение работает как положено, а также передает тот же аргумент командной строки, что и мое приложение.

Я заметил, что Write-Host «съедает» все новые строки, которые появляются в виде многострочной строки из моего приложения.

Вместо

PyTorch Load Model (release)
Checking input arguments
Usage: model [--help] [--version] [--model-path VAR] [--png-path VAR]

Optional arguments:
  -h, --help        shows help message and exits
  -v, --version     prints version information and exits
  -m, --model-path  Path to PTH TorchScript model
  -i, --png-path    Path to PNG image to be processed by the model

я получаю

Usage: model [--help] [--version] [--model-path VAR] [--png-path VAR]  Optional arguments:   -h, --help        shows help message and exits    -v, --version     prints version information and exits    -m, --model-path  Path to PTH TorchScript model    -i, --png-path    Path to PNG image to be processed by the model

Как сохранить новые строки?

🤔 А знаете ли вы, что...
PowerShell был создан компанией Microsoft в 2006 году и первоначально назывался 'Monad'.


1
52
3

Ответы:

Решено

Как предполагает @nimizen, лучшим вариантом будет трубопровод: (./model.exe --help) | write-host

В качестве альтернативного решения вы можете использовать ((./model.exe --help) -join "`r`n")


Вместо Write-Host вы можете использовать Write-Output, который просто передает значения в выходной поток. В то время как Write-Host превращает данные только в вывод на экран, и если вы не меняете цвета шрифта, это никогда не понадобится.


Полезный ответ Сиртао показывает эффективные решения.


Что касается того, что вы пробовали:

  • Когда PowerShell вызывает внешнюю программу, она построчно передает выходные данные стандартного вывода в конвейер PowerShell.

  • При заключении такого вызова в (...) — например, для передачи вывода в качестве аргумента команды, как в этом случае — строки обязательно собираются в массив (типа [object[]]), при условии, что существует две или более строк.

  • Write-Host, если в качестве аргумента передан массив, печатает (строчные) элементы массива в одной строке, каждый из которых разделен одним пробелом — вот что вы видели:

    • Простой пример:

      # -> 'foo bar'
      Write-Host @('foo', 'bar')
      
    • Чтобы добиться многострочного вывода (оба метода показаны в ответе Сиртао):

      • Либо: предоставьте выходные данные, полученные в результате вызова внешней программы (например, ./model.exe --help) через конвейер , который заставляет Write-Host печатать каждый входной объект конвейера в отдельной строке.

      • Или: Явно соедините строки, выводимые внешними программами, с символами новой строки, чтобы сформировать одну многострочную строку, которая Write-Host печатается как есть.

        • В качестве альтернативы решению -join в ответе Сиртао вы можете использовать командлет Out-String; например.:

           Write-Host -NoNewLine (./model.exe --help | Out-String)
          
          • Обратите внимание на использование -NoNewLine, которое компенсирует тот досадный факт, что Out-String добавляет завершающую новую строку к создаваемой многострочной выходной строке; это проблемное поведение обсуждается в выпуске GitHub № 14444.

Дополнительное чтение: Соответствующее использование Write-Host для создания цветного вывода stderr: