wake-up-neo.com

Welches sollte ich verwenden: "Write-Host", "Write-Output" oder "[Konsole] :: WriteLine"?

Ich versuche mich mit PowerShell auseinanderzusetzen. Eine einfache Sache, mit der ich mich abmühe, ist, dass es verschiedene Möglichkeiten gibt, Nachrichten auszugeben. Welche sollte ich verwenden und was ist der Unterschied, und gibt es eine konventionelle Methode, dies zu tun?

Ich stelle auch fest, dass ich Folgendes verwende:

write-Host "count=" + $count

Der + wird in die Ausgabe aufgenommen. Warum ist das? Sollte der Ausdruck nicht so ausgewertet werden, dass er eine einzelne verkettete Zeichenfolge erzeugt, bevor er ausgeschrieben wird?

177
Scott Langham

Write-Output sollte verwendet werden, wenn Sie Daten in der Rohrleitung senden möchten, diese jedoch nicht unbedingt auf dem Bildschirm anzeigen möchten. Die Pipeline schreibt sie schließlich in out-default, wenn vorher nichts anderes verwendet wird. Write-Host sollte verwendet werden, wenn Sie das Gegenteil tun möchten. [console]::WriteLine ist im Wesentlichen das, was Write-Host hinter den Kulissen macht.

Führen Sie diesen Demonstrationscode aus und überprüfen Sie das Ergebnis. 

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 

Sie müssen die Verkettung in Klammern einschließen, damit PowerShell die Verkettung verarbeitet, bevor Sie die Parameterliste für Write-Host kennzeichnen.

write-Host ("count=" + $count)

BTW - Sehen Sie dieses Video von Jeffrey Snover und erklären Sie, wie die Pipeline funktioniert. Als ich mit PowerShell angefangen habe, habe ich festgestellt, dass dies die nützlichste Erklärung für die Funktionsweise der Pipeline ist.

247
Andy Arismendi

Abgesehen von dem, was Andy erwähnt hat, gibt es noch einen anderen Unterschied, der wichtig sein könnte: Der write-Host schreibt direkt in den Host und gibt nichts zurück, was bedeutet, dass Sie die Ausgabe nicht umleiten können, z.

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

Jetzt in PowerShell ausführen:

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

Wie Sie sehen, können Sie sie nicht in eine Datei umleiten. Dies ist vielleicht überraschend für jemanden, der nicht aufpasst. 

Wenn Sie stattdessen die Schreibausgabe verwenden, wird die Umleitung wie erwartet ausgeführt.

28
KFL

Hier ist eine andere Möglichkeit, das Äquivalent von Write-Output zu erreichen. Geben Sie einfach Ihren String in Anführungszeichen ein:

"count=$count"

Sie können sicherstellen, dass dies genauso funktioniert wie Write-Output, indem Sie dieses Experiment ausführen:

"blah blah" > out.txt

Write-Output "blah blah" > out.txt

Write-Host "blah blah" > out.txt

Die ersten beiden geben "bla bla" in out.txt aus, die dritte jedoch nicht.

"help Write-Output" gibt einen Hinweis auf dieses Verhalten:

Dieses Cmdlet wird normalerweise in Skripts verwendet, um Zeichenfolgen und andere .__ anzuzeigen. Objekte auf der Konsole. Das Standardverhalten lautet jedoch Wenn Sie die Objekte am Ende einer Pipeline anzeigen, ist es normalerweise nicht erforderlich, um das Cmdlet zu verwenden.

In diesem Fall ist der String selbst "count = $ count" das Objekt am Ende einer Pipeline und wird angezeigt.

14
FarmerBob

Write-Output und [Console] :: WriteLine () zeigen in meinen Tests eine wesentlich bessere Leistung als Write-Host.

Je nachdem, wie viel Text Sie schreiben müssen, kann dies wichtig sein.

Darunter das Ergebnis von jeweils 5 Tests für Write-Host, Write-Output und [Console] :: WriteLine ().

In meiner begrenzten Erfahrung habe ich herausgefunden, dass ich bei der Arbeit mit beliebigen Daten aus der realen Welt die Cmdlets aufgeben und direkt auf die Befehle der unteren Ebene zugreifen muss, um eine anständige Leistung aus meinen Skripts zu erzielen.

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
3
tom

Für die Verwendung von Write-Host erzeugt PSScriptAnalyzer die folgende Diagnose:

Vermeiden Sie die Verwendung von Write-Host, da dies möglicherweise nicht auf allen Hosts funktioniert, nicht funktioniert, wenn kein Host vorhanden ist, und (vor PS 5.0) nicht unterdrückt, erfasst oder umgeleitet werden kann. Verwenden Sie stattdessen Write-Output, Write-Verbose oder Write-Information.

Weitere Informationen finden Sie in der Dokumentation hinter dieser Regel. Auszüge für die Nachwelt:

Die Verwendung von Write-Host wird dringend empfohlen, es sei denn, Sie verwenden Befehle mit dem Show-Verb. Das Show-Verb bedeutet explizit "auf dem Bildschirm ohne andere Möglichkeiten anzeigen".

Bei Befehlen mit dem Show-Verb wird diese Prüfung nicht angewendet.

Jeffrey Snover hat einen Blogbeitrag Write-Host als schädlich , in dem er behauptet, dass Write-Host fast immer das Falsche ist, weil er die Automatisierung stört und weitere Erklärungen für die Diagnose liefert ist eine gute Zusammenfassung.

1
Drew Noakes

In Bezug auf [Console] :: WriteLine () - Sie sollten es verwenden, wenn Sie Pipelines in CMD (nicht in Powershell) verwenden möchten. Angenommen, Sie möchten, dass Ihre PS1 eine Menge Daten in stdout streamen soll, und ein anderes Dienstprogramm, um sie zu verwenden/umzuwandeln. Wenn Sie im Skript Write-Host verwenden, wird es wesentlich langsamer.

0
Mike Twc