В настоящее время я пытаюсь использовать сценарий PowerShell для автоматизации ежедневного обслуживания моих приложений.
Итак, у меня внутри есть что-то похожее на этот псевдокод:
statement
statement
$variable
$(command $variable) #edited
# this is external .bat file that I'm passing the variable as param.
statement
Дело в том, что подкоманда выполняется, но не передает свой вывод в main thread
, поэтому я получаю «паузу», пока она выполняется.
normal output
normal output
**wait while subcommand gets executed**
normal output
Как я могу записать вывод подкоманды в основной стандартный вывод моего скрипта?
Я немного исследовал, и появился Tee-Object, но я думаю, что он в основном предназначен для одновременной записи файла, пока вы показываете свою вещь через стандартный вывод, что полезно для целей регистрации и, возможно, понадобится в будущем.
В моем конкретном случае я сейчас не знаю, можно ли использовать Tee-Object.
Судя по тому, как вы написали свой псевдоскрипт, $(command)
является параметром третьего statement
. Либо statement
должен вывести все, что он получает в качестве первого параметра, либо вы должны отдельно учесть необходимость печати выходных данных.
Чтобы сделать последнее, присвойте его переменной, напечатайте переменную, а затем передайте ее в качестве параметра в statement
:
statement1
statement2
$s3param = $(command) # capture the output of command
$s3param # print the (captured) output of command
statement3 $s3param # pass the (captured) output of command as a parameter to statement3
statement4
⋮
(В зависимости от command
вам может не понадобиться $()
вокруг него)
Джефф, ты совершенно прав. Моя подкоманда не является параметром, передаваемым в оператор, это сам по себе оператор, но он действительно должен находиться внутри $(), поскольку для вызова требуется внешний .bat.
Предисловие:
Ответ ниже, а также Джеффа Зейтлина основаны на более ранней форме вопроса со случайно другой предпосылкой:
$(...)
command $(command)
), в идеале в потоковом режиме (испуская каждый выходной объект, как только он становится доступным).Чтобы обратиться к текущей форме вопроса:
Использование $(...)
, оператора подвыражения , имеет побочный эффект, заключающийся в предварительном сборе всех выходных данных перед их выводом в поток вывода успеха.
Автономная команда, такая как вызов пакетного файла (с аргументами или без них), не требует заключения в $(...)
; Основное использование $(...)
— внутри расширяемых (интерполирующих) строк в двойных кавычках («...»).
Таким образом, простой пропуск $(...)
должен привести к желаемому поведению потоковой передачи.
Если вы хотите, чтобы так называемые операторы языка (например, оператор switch ) предоставляли входные данные другой команде в конвейере (который напрямую не поддерживается) с потоковым поведением, заключите их в блок сценария ({ ... }
) и вызвать последний с помощью &
, оператора вызова; вы также можете использовать тот же метод для ввода данных из нескольких команд таким образом; например.:
# Enclosure in & { ... } provides streaming output from
# the enclosed command / statements, as evidenced by the fact
# that the first Get-Date call's output prints right away,
# before pausing.
& { Get-Date; pause; Get-Date } | Write-Output
Ответ на исходный вопрос:
Полезный ответ Джеффа Зейтлина показывает, как сначала захватить весь вывод команды внутри $(...)
, затем вывести его в поток вывода успеха (аналог стандартного вывода PowerShell) и, наконец, передать его в качестве аргумента, как и раньше.
Альтернативно, ЕСЛИ:
$(...)
, как только будет создан каждый выходной объект, и...вы можете использовать Tee-Object и передать консоль/терминальное устройство в качестве аргумента параметра -FilePath
, который затем выводит каждый входной объект на терминал, а также выводит его в поток вывода успеха для дальнейшей программной обработки:
Вот простой пример:
# PowerShell 7
Write-Host -ForegroundColor Yellow $(
1, 2, 3 | Tee-Object -FilePath ($IsWindows ? '\\.\CON': '/dev/tty')
)
Пример команды (массив 1, 2, 3
) выводится на терминал в потоковом режиме, прежде чем Write-Host
сразу получает собранные выходные данные в виде одного аргумента.
Обратите внимание, что, как отмечает Джефф, использование $(...)
может не потребоваться для заключения вашей команды, что позволяет вместо этого использовать более эффективный и не имеющий побочных эффектов (...)
; действительно, в рассматриваемом случае, поскольку команда состоит только из одного конвейера, (...)
достаточно - см. этот ответ для получения дополнительной информации.
Огромное спасибо, действительно, решение моей глупой проблемы заключалось в использовании структуры & {}
вместо $( )
. Огромное спасибо за ваше время и терпение.
Если я понимаю вопрос, без какого-либо кода вы хотите использовать & { }
(или функцию) вместо $( )
, чтобы увидеть результат в реальном времени? (Но зачем вообще использовать $( ), если вы не хотите объединить несколько операторов?)
$(1;sleep 1;2;sleep 1;3) # dumps output all at once at the end
1
2
3
& {1;sleep 1;2;sleep 1;3} # see output as it's running
1
2
3
Спасибо. Также обратите внимание, что вы можете помочь будущим читателям, четко обозначив, какой ответ, если таковой имеется, решил вашу проблему, а именно приняв его.