В чем разница между «Write-Host», «Write-Output» или «[console] :: WriteLine»?


194

Существует несколько способов вывода сообщений. Что такое эффективная разница между выводя что - то с помощью Write-Host, Write-Outputили [console]::WriteLine?

Я также заметил, что если я использую:

write-host "count=" + $count

+Получает включены в вывод. Почему это? Разве выражение не должно быть вычислено, чтобы произвести единственную объединенную строку прежде, чем это будет записано?


4
Write-Outputкогда вы излучаете результаты. Write-Hostкогда вы излучаете информацию регистрации. Никогда не используйте [console]::writeline().
JohnL

2
@JohnL, почему мы никогда не должны использовать [console] :: writeline ()?
Дэвид Клемпфнер

3
@Backwards_Dave Потому что у вас есть Write-Host .... Ладно, у меня могло сложиться впечатление, что оно показало новое окно консоли (это было довольно давно). Этого не происходит, но факт остается фактом, что это не идиома PowerShell, и вы ничего не можете сделать с [console]::writeline("hello world")этим, с которым вы не можете делать Write-Host "hello world". Другой, более подходящий, более недавно применимый ответ заключается в том, что данные write-hostпереносятся write-informationтаким образом, что их данные помещаются в поток, таким write-errorобразом, вы можете захватывать их и использовать в другом месте. [console]::writeline()не делает этого
JohnL

Ответы:


269

Write-Outputследует использовать, если вы хотите отправить данные по конвейеру, но не обязательно хотите отобразить их на экране. Конвейер в конце концов запишет это, out-defaultесли больше ничего не использует это сначала.

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

[console]::WriteLineпо сути то, что Write-Hostделает за кадром.

Запустите этот демонстрационный код и проверьте результат.

function Test-Output {
    Write-Output "Hello World"
}

function Test-Output2 {
    Write-Host "Hello World" -foreground Green
}

function Receive-Output {
    process { Write-Host $_ -foreground Yellow }
}

#Output piped to another function, not displayed in first.
Test-Output | Receive-Output

#Output not piped to 2nd function, only displayed in first.
Test-Output2 | Receive-Output 

#Pipeline sends to Out-Default at the end.
Test-Output 

Вам необходимо заключить операцию конкатенации в круглые скобки, чтобы PowerShell обрабатывал конкатенацию перед токенизацией списка параметров Write-Hostили для использования интерполяции строк.

write-host ("count=" + $count)
# or
write-host "count=$count"

Кстати - посмотрите это видео Джеффри Сновера, объясняющего, как работает конвейер. Когда я начал изучать PowerShell, я обнаружил, что это наиболее полезное объяснение того, как работает конвейер.


В Azure WebJob [console] :: WriteLine работает, но Write-Host приведет к ошибке: Внутренняя ошибка Win32 «Неверный дескриптор» 0x6 произошла при установке атрибутов символа для буфера вывода консоли. Не спрашивай меня почему.
Гил Ройто

Поправьте меня, если я ошибаюсь, но я считаю, Write-Outputчто это значение по умолчанию, например, если у вас есть PsObject, и вы просто выплевываете его на экран, делая это, $objectон фактически делает то же самое, что и этот Write-Output $object. Стоит упомянуть
Каньон Колоб

1
Есть новое руководство: по возможности избегайте использования Write-Output. См. Github.com/PoshCode/PowerShellPracticeAndStyle/issues/… > Использовать возврат только для завершения выполнения. > Избегайте записи-вывода (...). Вместо этого, когда вы хотите сделать вывод более понятным, просто назначьте вывод переменной с соответствующим именем. и поместите эту переменную в строку, чтобы обозначить явный вывод. > Write-Output -NoEnumerate не работает в PowerShell 6 и выполняется в течение 16 месяцев или дольше - его не планируется исправлять. В итоге:> НЕ ИСПОЛЬЗУЙТЕ Write-Output - НИКОГДА.
Йерун Wiert Pluimers

28

Помимо того, что упомянул Энди, есть еще одно отличие, которое может иметь важное значение - write-host напрямую пишет на хост и ничего не возвращает, а это означает, что вы не можете перенаправить вывод, например, в файл.

---- script a.ps1 ----
write-host "hello"

Теперь запустите в PowerShell:

PS> .\a.ps1 > someFile.txt
hello
PS> type someFile.txt
PS>

Как видно, вы не можете перенаправить их в файл. Это может быть удивительно для тех, кто не осторожен.

Но если вместо этого использовать запись-вывод, перенаправление будет работать так, как ожидается.


Можно записать выходные данные Write-Host, если вы используете Start-Process Powershell. \ A.ps1 -RedirectStandardOutput somefile.txt Однако есть проблемы с кодировкой (файл будет в SystemDefaultEncoding).
MKesper

16

Вот еще один способ сделать эквивалент записи-вывода. Просто поместите вашу строку в кавычки:

"count=$count"

Вы можете убедиться, что это работает так же, как Write-Output, запустив этот эксперимент:

"blah blah" > out.txt

Write-Output "blah blah" > out.txt

Write-Host "blah blah" > out.txt

Первые два будут выводить «бла-бла» в out.txt, а третье - нет.

«help Write-Output» дает подсказку о таком поведении:

Этот командлет обычно используется в сценариях для отображения строк и других объектов на консоли. Однако поскольку поведение по умолчанию заключается в отображении объектов в конце конвейера, обычно нет необходимости использовать командлет.

В этом случае сама строка «count = $ count» является объектом в конце конвейера и отображается.


6

Для использования Write-Host, PSScriptAnalyzerпроизводит следующую диагностику:

Избегайте использования, Write-Hostпотому что он может работать не на всех хостах, не работает, когда хоста нет, и (до PS 5.0) не может быть подавлен, захвачен или перенаправлен. Вместо этого используйте Write-Output, Write-Verboseили Write-Information.

См. Документацию за этим правилом для получения дополнительной информации. Выдержки для потомков:

Использование Write-Hostочень не рекомендуется, если только в использовании команд с Showглаголом. ShowГлагол явно означает «показать на экране, без каких - либо других возможностей».

Команды с Showглаголом не применяют эту проверку.

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


3

Из моего тестирования Write-Output и [Console] :: WriteLine () работают намного лучше, чем Write-Host.

В зависимости от того, сколько текста вам нужно написать, это может быть важно.

Ниже приведены результаты по 5 тестов для каждого типа Write-Host, Write-Output и [Console] :: WriteLine ().

Из своего ограниченного опыта я обнаружил, что при работе с любыми данными из реального мира мне нужно отказаться от командлетов и перейти к командам более низкого уровня, чтобы добиться приличной производительности от моих сценариев.

measure-command {$count = 0; while ($count -lt 1000) { Write-Host "hello"; $count++ }}

1312ms
1651ms
1909ms
1685ms
1788ms


measure-command { $count = 0; while ($count -lt 1000) { Write-Output "hello"; $count++ }}

97ms
105ms
94ms
105ms
98ms


measure-command { $count = 0; while ($count -lt 1000) { [console]::WriteLine("hello"); $count++ }}

158ms
105ms
124ms
99ms
95ms

1
Write-Outputи Write-Hostслужат различным целям, поэтому нет смысла сравнивать их эффективность. Да, прямое использование типов .NET и их методов происходит быстрее, но вы упускаете возможности более высокого уровня, которые могут предоставить командлеты PowerShell. [Console]::WriteLine()Это похоже на Write-Hostрассматриваемый случай, но не будет работать при любых обстоятельствах, потому что не все хосты PowerShell являются консолями .
mklement0

0

Относительно [Console] :: WriteLine () - вы должны использовать его, если вы собираетесь использовать конвейеры в CMD (не в powershell). Скажем, вы хотите, чтобы ваш ps1 передавал много данных на стандартный вывод, а некоторые другие утилиты использовали их для преобразования / преобразования. Если вы используете Write-Host в скрипте, это будет намного медленнее.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.