Was ist der Unterschied zwischen "Write-Host", "Write-Output" oder "[console] :: WriteLine"?

192

Es gibt verschiedene Möglichkeiten, Nachrichten auszugeben. Was ist die effektive Differenz etwas über zwischen ausgeben Write-Host, Write-Outputoder [console]::WriteLine?

Ich bemerke auch, dass wenn ich benutze:

write-host "count=" + $count

Das +wird in die Ausgabe aufgenommen. Warum ist das? Sollte der Ausdruck nicht ausgewertet werden, um eine einzelne verkettete Zeichenfolge zu erzeugen, bevor er ausgeschrieben wird?

Scott Langham
quelle
4
Write-Outputwenn Sie Ergebnisse ausgeben. Write-Hostwenn Sie Protokollinformationen ausgeben. Niemals benutzen [console]::writeline().
JohnL
2
@ JohnL warum sollten wir niemals [console] :: writeline () verwenden?
David Klempfner
3
@Backwards_Dave Weil Sie Write-Host haben ... Ok, ich hatte vielleicht den Eindruck, dass es ein neues Konsolenfenster zeigte (es ist ziemlich lange her). Das passiert nicht, aber die Tatsache bleibt, dass es nicht die Powershell-Sprache ist und es nichts gibt, mit [console]::writeline("hello world")dem Sie nichts anfangen können Write-Host "hello world". Eine andere, bessere und in jüngerer Zeit zutreffende Antwort ist, dass write-hostWraps write-informationso verwendet werden, dass ihre Daten in einen Stream gestellt werden, write-errordamit Sie sie erfassen und an anderer Stelle verwenden können. [console]::writeline()macht das nicht
JohnL

Antworten:

267

Write-Outputsollte verwendet werden, wenn Sie Daten in der Rohrleitung senden möchten, diese aber nicht unbedingt auf dem Bildschirm anzeigen möchten. Die Pipeline schreibt es schließlich, out-defaultwenn nichts anderes es zuerst verwendet.

Write-Host sollte verwendet werden, wenn Sie das Gegenteil tun möchten.

[console]::WriteLineist im Wesentlichen das, was Write-Hosthinter den Kulissen geschieht.

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 den Verkettungsvorgang in Klammern setzen, damit PowerShell die Verkettung verarbeitet, bevor Sie die Parameterliste für die Token- Write-HostInterpolation tokenisieren oder die Zeichenfolgeninterpolation verwenden

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

Übrigens - Sehen Sie sich dieses Video von Jeffrey Snover an, in dem erklärt wird, wie die Pipeline funktioniert. Als ich anfing, PowerShell zu lernen, fand ich, dass dies die nützlichste Erklärung für die Funktionsweise der Pipeline ist.

Andy Arismendi
quelle
In einer Azure WebJob [Konsole] :: WriteLine funktioniert, aber Write-Host führt zu einem Fehler: Der interne Win32-Fehler "Das Handle ist ungültig" 0x6 ist beim Festlegen der Zeichenattribute für den Konsolenausgabepuffer aufgetreten. Frag mich nicht warum.
Gil Roitto
Korrigieren Sie mich, wenn ich falsch Write-Outputliege , aber ich glaube, dies ist die Standardeinstellung, z. B. wenn Sie ein PsObject haben und es einfach auf den Bildschirm ausspucken, $objectwird es tatsächlich das Gleiche tun Write-Output $object. Könnte erwähnenswert sein
Kolob Canyon
1
Es gibt neue Richtlinien: Vermeiden Sie die Verwendung, Write-Outputwenn dies möglich ist. Siehe github.com/PoshCode/PowerShellPracticeAndStyle/issues/… > Verwenden Sie return nur, um die Ausführung zu beenden. > Schreibausgabe vermeiden (...). Wenn Sie die Ausgabe klarer gestalten möchten, weisen Sie die Ausgabe stattdessen einer relevanten Variablen zu. und setzen Sie diese Variable in eine Zeile für sich, um eine explizite Ausgabe zu signalisieren. > Write-Output -NoEnumerate ist in PowerShell 6 fehlerhaft und seit 16 Monaten oder länger in Betrieb - es gibt keinen Plan, dies zu beheben. Zusammenfassend:> VERWENDEN SIE KEINE Schreibausgabe - NIEMALS.
Jeroen Wiert Pluimers
28

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

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

Führen Sie jetzt PowerShell aus:

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

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

Wenn Sie jedoch auf Schreibausgabe umstellen, funktioniert die Umleitung wie erwartet.

KFL
quelle
Es ist möglich, die Write-Host-Ausgabe zu erfassen, wenn Sie Start-Process Powershell verwenden. \ A.ps1 -RedirectStandardOutput somefile.txt Es gibt jedoch Probleme mit der Codierung (Datei befindet sich in SystemDefaultEncoding).
MKesper
16

Hier ist eine andere Möglichkeit, das Äquivalent von Write-Output zu erreichen. Setzen Sie einfach Ihre Zeichenfolge in Anführungszeichen:

"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" an out.txt aus, die dritte nicht.

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

Dieses Cmdlet wird normalerweise in Skripten verwendet, um Zeichenfolgen und andere Objekte auf der Konsole anzuzeigen. Da das Standardverhalten jedoch darin besteht, die Objekte am Ende einer Pipeline anzuzeigen, ist es im Allgemeinen nicht erforderlich, das Cmdlet zu verwenden.

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

FarmerBob
quelle
6

Für Verwendungen von Write-Host, PSScriptAnalyzererzeugt die folgende Diagnose:

Vermeiden Sie die Verwendung, Write-Hostda 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-Verboseoder Write-Information.

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

Von der Verwendung von Write-Hostwird dringend abgeraten, es sei denn, Sie verwenden Befehle mit dem ShowVerb. Das ShowVerb bedeutet explizit "auf dem Bildschirm anzeigen, ohne andere Möglichkeiten".

Bei Befehlen mit dem ShowVerb wird diese Prüfung nicht angewendet.

Jeffrey Snover hat einen Blog-Beitrag Write-Host als schädlich eingestuft, in dem er behauptet, Write-Host sei fast immer das Falsche, weil er die Automatisierung stört und mehr Erklärungen für die Diagnose liefert. Das Obige ist jedoch eine gute Zusammenfassung.

Drew Noakes
quelle
3

Nach meinen Tests haben Write-Output und [Console] :: WriteLine () eine viel bessere Leistung als Write-Host.

Je nachdem, wie viel Text Sie zum Schreiben benötigen, kann dies wichtig sein.

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

Aufgrund meiner begrenzten Erfahrung habe ich festgestellt, dass ich bei der Arbeit mit Daten aus der realen Welt die Cmdlets verlassen und direkt zu den Befehlen der unteren Ebene wechseln muss, um eine anständige Leistung meiner Skripte 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
Tom
quelle
1
Write-Outputund Write-Hostdienen verschiedenen Zwecken, so dass es keinen Sinn macht, ihre Leistung zu vergleichen. Ja, die direkte Verwendung von .NET-Typen und ihren Methoden ist schneller, aber Sie verpassen die übergeordneten Funktionen, die PowerShell-Cmdlets bieten können. [Console]::WriteLine()ähnelt Write-Hostdem vorliegenden Fall, funktioniert jedoch nicht unter allen Umständen, da nicht alle PowerShell-Hosts Konsolen sind .
mklement0
0

In Bezug auf [Console] :: WriteLine () - sollten Sie es verwenden, wenn Sie Pipelines in CMD (nicht in Powershell) verwenden möchten. Angenommen, Ihr ps1 soll viele Daten an stdout streamen und ein anderes Dienstprogramm, um sie zu konsumieren / transformieren. Wenn Sie Write-Host im Skript verwenden, ist es viel langsamer.

Mike Twc
quelle