Использование Write-Output очень ненадежно по сравнению с Write-Host
Мне указали на вопрос, который предлагает использовать Write-Output поверх Write-Host, если я хочу, чтобы команды работали последовательно (поскольку Write-Host не помещает вывод в конвейер, в то время как другие команды делают это, что означает, что вывод Write-Host может происходят до или после других команд, находящихся в конвейере, что приводит к очень беспорядочным выводам): порядок выполнения команд внутри блока сценария PowerShell
Следуя этому совету, я сделал простую функцию, используя Write-Output, чтобы имитировать цветовой синтаксис Write-Host. Для упорядочивания это работает хорошо, поэтому вывод команд теперь является последовательным, но цветовой вывод теперь ужасен с записью-выводом, поэтому, если я вообще использую какой-либо BackgroundColor, результаты очень некрасиво распределяются по экрану. Write-Host был плотным и надежным с цветным выводом и не просачивался в другие части консоли, поэтому использование Write-Output с цветом делает вывод на консоль действительно уродливым / неуклюжим.
Нужно ли мне каким-то образом сбросить $host.ui перед выходом из функции, или кто-нибудь может предложить способ изменить эту функцию, чтобы цвета оставались плотно прилегающими к областям, для которых они необходимы, и не просачивались в другие области консоли?
function Write-Color ($text, $ForegroundColor, $BackgroundColor) {
$defaultFore = $host.ui.RawUI.ForegroundColor
$defaultBack = $host.ui.RawUI.BackgroundColor
if ($ForegroundColor -ne $null) { $host.ui.RawUI.ForegroundColor = $ForegroundColor }
if ($BackgroundColor -ne $null) { $host.ui.RawUI.BackgroundColor = $BackgroundColor }
Write-Output $text
$host.ui.RawUI.ForegroundColor = $defaultFore
$host.ui.RawUI.BackgroundColor = $defaultBack
}
например
Write-Color "The dog sat on the couch" -ForegroundColor Red -BackgroundColor White
1 ответ
Write-Host
является правильным инструментом для создания (возможно, цветного) вывода для отображения - в отличие от вывода данных через поток вывода успеха PowerShell, через вызовы командлетов и выражения (необязательно через явноеWrite-Output
звонки, но это редко нужно).
Этот ответ объясняет, что если вы смешаете Write-Host
и вывод успешного потока, в PowerShell v5+ то, что выводится на консоль, может отображаться в другом порядке.
Это побочный эффект неявно применяемого табличного форматирования, которое ситуативно является асинхронным, в попытке собрать некоторые данные перед выводом на печать, чтобы определить подходящую ширину столбца. Это происходит только с типами вывода, которые (а) не имеют предопределенных данных формата и (б) имеют 4 или меньше свойств (поскольку типы с большим количеством свойств по умолчанию используют форматирование списка).
Проблемное поведение обсуждается в этом выпуске GitHub; хотя все еще есть надежда на решение, долгое время не было никакой активности.
В PowerShell 7.0 нет хорошего решения этой проблемы:
Есть два - неоптимальных - обходных пути:
(a) Передайте отдельные команды, которые запускают асинхронное поведение, в
... | Out-Host
.Например, в следующей команде команда с
Select-Object
звонок должен быть отправлен наOut-Host
чтобы правильно появиться между двумяWrite-Host
вызывает на экране:Write-Host '------- 1'; Get-Item . | Select-Object FullName | Out-Host; Write-Host '------- 2'
Обратная сторона: использование
Out-Host
означает, что вы теряете возможность захватывать или перенаправлять вывод команды, потому что он отправляется непосредственно на хост (отображение). Кроме того, сложно (а) знать, какие команды вызывают проблему, и (б) не забыть применить обходной путь к каждой из них.
(b) Заменить
Write-Host
вызовы с отправкой строк со встроенными escape-последовательностями VT (Virtual Terminal) (для раскрашивания) в поток вывода успеха.Примечание. Требуется Windows PowerShell v5.1 в Windows 10 или PowerShell [Core] v6+
Оборотная сторона: (цветные) строки становятся частью вывода данных кода и, следовательно, включаются при захвате / перенаправлении вывода.
# Windows PowerShell 5.1: [char] 0x1b produces an ESC char. $green = [char] 0x1b + '[32m'; $reset = [char] 0x1b + '[m' # Print "green" in green. "It ain't easy being ${green}green${reset}." # PowerShell 6+: `e can be used inside "..." for ESC. $yellow = "`e[33m"; $reset = "`e[m" # Print "yellow" in yellow. "They call me mellow ${yellow}yellow${reset}."
- Тот факт, что эти строки содержат символы ESC. может фактически использоваться для фильтрации строк для отображения из потока данных (при условии, что ваши фактические данные не содержат символы ESC.), вдоль строк
... | Where-Object { -not ($_ -is [string] -and $_ -match '\e') }
- Тот факт, что эти строки содержат символы ESC. может фактически использоваться для фильтрации строк для отображения из потока данных (при условии, что ваши фактические данные не содержат символы ESC.), вдоль строк
Встраивание управляющих последовательностей VT позволяет вам выборочно раскрашивать части ваших строк.
Достижение того же эффекта с Write-Host
потребуется несколько звонков с-NoNewline
.
Сторонний командлет (модуль) Write-ColoredOutput
подражает Write-Host
синтаксис и использует [console]
type для включения и выключения раскраски при отправке строки в поток вывода успеха.
Это хорошо подходит для записи всей строки заданным цветом, но вы не можете объединить части разного цвета в одну строку, потому что каждая строка, индивидуально записанная в поток вывода успеха, неизменно печатается в отдельной строке.
Если вам нужна удобная оболочка для встраивания последовательностей VT непосредственно в строки, вы можете адаптировать Write-HostColored
функцию из этого ответа, заменивWrite-Host
вызовы, которые происходят за кулисами с последовательностями VT.