Яка різниця між "Write-Host", "Write-Output" або "[console] :: WriteLine"?


193

Існує ряд різних способів виведення повідомлень. Що таке ефективна різниця між виводячи що - то з допомогою Write-Host, Write-Outputабо [console]::WriteLine?

Я також помічаю, що якщо я використовую:

write-host "count=" + $count

+Отримує включені в висновок. Чому це? Чи не слід вираз оцінювати таким чином, щоб він створив єдиний об'єднаний рядок до того, як він виписаний?


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

2
@JohnL, чому ми ніколи не повинні використовувати [console] :: pisal ()?
Девід Клепмпнер

3
@Backwards_Dave Оскільки у вас є Write-Host .... Ок, я, мабуть, був під певним враженням, що воно показало нове вікно консолі (це було досить давно). Це не відбувається, але факт залишається фактом , що це не ідіома і PowerShell немає нічого , що ви можете зробити з , [console]::writeline("hello world")що ви не можете зробити з Write-Host "hello world". Ще одна, краща, останнім часом застосовна відповідь - це write-hostобробка write-informationданих, щоб її дані надходили на потік на зразок, write-errorщоб ви могли їх захопити та використовувати в іншому місці. [console]::writeline()не робить цього
JohnL

Відповіді:


268

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"

BTW - Перегляньте це відео Джефрі Сновер, який пояснює, як працює трубопровід. Ще коли я почав вивчати PowerShell, я виявив, що це є найбільш корисним поясненням того, як працює трубопровід.


У Azure WebJob [консоль] :: WriteLine працює, але Write-Host призведе до помилки: Внутрішня помилка Win32 "Обробка недійсна" 0x6 сталася під час встановлення атрибутів символів для вихідного буфера консолі. Не питайте мене, чому.
Гіл Ройтто

Виправте мене, якщо я помиляюся, але я вважаю, що Write-Outputце за замовчуванням, наприклад, якщо у вас є PsObject, і ви просто виплюнете його на екран, зробивши це, $objectвін насправді зробить те саме, що і це Write-Output $object. Можливо, варто згадати
Колонь Каньйон

1
Є нові вказівки: уникайте використання, Write-Outputколи це можливо. Див. Github.com/PoshCode/PowerShellPracticeAndStyle/isissue/… > Використовувати return лише для завершення виконання. > Уникайте запису-виводу (...). Натомість, коли ви хочете зробити висновок чіткішим, просто призначте результат відповідної названої змінної. і поставити цю змінну на рядок сама по собі, щоб сигналізувати явний вихід. > Write-Output -NoEnumerate порушено в PowerShell 6 і вже 16 місяців і довше - планувати це не можна. Підсумовуючи:> НЕ ВИКОРИСТОВУЮВАТИ Виписування - ВСЕ.
Jeroen Wiert Pluimers

28

Крім того, що Енді згадував, є ще одна відмінність, яка може бути важливою - запис-хост безпосередньо записує на хост і нічого не повертає, що означає, що ви не можете перенаправити вихід, наприклад, на файл.

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

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

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

Як видно, ви не можете перенаправити їх у файл. Це може бути дивно для того, хто не є обережним.

Але якщо перейти на використання запису-виводу замість цього, ви отримаєте перенаправлення працює, як очікувалося.


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

16

Ось ще один спосіб досягти еквівалента Write-Output. Просто поставте рядок у лапки:

"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 (не в powerhell). Скажімо, ви хочете, щоб ваш ps1 передав багато даних для stdout, а якась інша утиліта споживала / перетворювала їх. Якщо ви використовуєте Write-Host в сценарії, це буде набагато повільніше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.