Quelle est la différence entre «Write-Host», «Write-Output» ou «[console] :: WriteLine»?

194

Il existe plusieurs manières de sortir des messages. Quelle est la différence réelle entre la sortie quelque chose par l' intermédiaire Write-Host, Write-Outputou [console]::WriteLine?

Je remarque également que si j'utilise:

write-host "count=" + $count

Le +est inclus dans la sortie. Pourquoi ça? L'expression ne devrait-elle pas être évaluée pour produire une seule chaîne concaténée avant d'être écrite?

Scott Langham
la source
4
Write-Outputlorsque vous émettez des résultats. Write-Hostlorsque vous émettez des informations de journalisation. N'utilisez jamais [console]::writeline().
JohnL
2
@JohnL pourquoi ne devrions-nous jamais utiliser [console] :: writeline ()?
David Klempfner
3
@Backwards_Dave Parce que vous avez Write-Host .... Ok, j'ai peut-être eu l'impression qu'il montrait une nouvelle fenêtre de console (c'était il y a assez longtemps). Cela n'arrive pas, mais le fait demeure que ce n'est pas l'idiome de PowerShell et que vous ne pouvez rien faire avec [console]::writeline("hello world")que vous ne puissiez pas faire Write-Host "hello world". Une autre réponse, meilleure et plus récemment applicable, est qu'elle write-hosts'enroule write-informationpour que ses données soient placées dans un flux, comme write-errorvous pouvez le capturer et l'utiliser ailleurs. [console]::writeline()ne fait pas ça
JohnL

Réponses:

269

Write-Outputdoit être utilisé lorsque vous souhaitez envoyer des données dans la canalisation, mais que vous ne souhaitez pas nécessairement les afficher à l'écran. Le pipeline finira par l'écrire out-defaultsi rien d'autre ne l'utilise en premier.

Write-Host doit être utilisé lorsque vous souhaitez faire le contraire.

[console]::WriteLineest essentiellement ce qui Write-Hostse fait dans les coulisses.

Exécutez ce code de démonstration et examinez le résultat.

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 

Vous devrez mettre l'opération de concaténation entre parenthèses, afin que PowerShell traite la concaténation avant de tokeniser la liste de paramètres pour Write-Host, ou d'utiliser l'interpolation de chaîne

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

BTW - Regardez cette vidéo de Jeffrey Snover expliquant le fonctionnement du pipeline. À l'époque où j'ai commencé à apprendre PowerShell, j'ai trouvé que c'était l'explication la plus utile du fonctionnement du pipeline.

Andy Arismendi
la source
Dans un Azure WebJob [console] :: WriteLine fonctionne mais Write-Host entraînera une erreur: L'erreur interne Win32 «Le handle n'est pas valide» 0x6 s'est produite lors de la définition des attributs de caractère pour le tampon de sortie de la console. Ne me demandez pas pourquoi.
Gil Roitto
Corrigez-moi si je me trompe, mais je crois que Write-Outputc'est la valeur par défaut, par exemple si vous avez un PsObject et que vous le crachez simplement à l'écran en faisant cela, $objectil fera en fait la même chose que cela Write-Output $object. Il vaut peut-être la peine de mentionner
Kolob Canyon
1
Il y a de nouveaux conseils: évitez d'utiliser Write-Outputlorsque c'est possible. Voir github.com/PoshCode/PowerShellPracticeAndStyle/issues/... > Utilisez return uniquement pour terminer l'exécution. > Évitez l'écriture-sortie (...). Au lieu de cela, lorsque vous souhaitez rendre la sortie plus claire, affectez simplement la sortie à une variable nommée de manière appropriée. et placez cette variable sur une ligne seule pour signaler une sortie explicite. > Write-Output -NoEnumerate est interrompu sur PowerShell 6 et ce depuis 16 mois ou plus - il n'est pas prévu de le réparer. En résumé:> N'UTILISEZ JAMAIS d'écriture-sortie.
Jeroen Wiert Pluimers
28

En dehors de ce qu'Andy a mentionné, il y a une autre différence qui pourrait être importante - write-host écrit directement sur l'hôte et ne renvoie rien, ce qui signifie que vous ne pouvez pas rediriger la sortie, par exemple, vers un fichier.

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

Maintenant, exécutez dans PowerShell:

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

Comme on le voit, vous ne pouvez pas les rediriger dans un fichier. Cela peut être surprenant pour quelqu'un qui ne fait pas attention.

Mais si vous utilisez plutôt la sortie d'écriture, la redirection fonctionnera comme prévu.

KFL
la source
Il est possible de capturer la sortie d'hôte d'écriture si vous utilisez Start-Process Powershell. \ A.ps1 -RedirectStandardOutput somefile.txt Il y a des problèmes avec l'encodage, cependant (le fichier sera dans SystemDefaultEncoding).
MKesper
16

Voici une autre façon d'accomplir l'équivalent de Write-Output. Mettez simplement votre chaîne entre guillemets:

"count=$count"

Vous pouvez vous assurer que cela fonctionne de la même manière que Write-Output en exécutant cette expérience:

"blah blah" > out.txt

Write-Output "blah blah" > out.txt

Write-Host "blah blah" > out.txt

Les deux premiers afficheront "bla bla" vers out.txt, mais le troisième ne le sera pas.

"help Write-Output" donne un indice de ce comportement:

Cette cmdlet est généralement utilisée dans les scripts pour afficher des chaînes et d'autres objets sur la console. Cependant, comme le comportement par défaut est d'afficher les objets à la fin d'un pipeline, il n'est généralement pas nécessaire d'utiliser l'applet de commande.

Dans ce cas, la chaîne elle-même "count = $ count" est l'objet à la fin d'un pipeline et est affichée.

FarmerBob
la source
6

Pour les utilisations de Write-Host, PSScriptAnalyzerproduit le diagnostic suivant:

Évitez d'utiliser, Write-Hostcar cela peut ne pas fonctionner sur tous les hôtes, ne pas fonctionner lorsqu'il n'y a pas d'hôte et (avant PS 5.0) ne peut pas être supprimé, capturé ou redirigé. Au lieu de cela, l' utilisation Write-Output, Write-Verboseou Write-Information.

Consultez la documentation derrière cette règle pour plus d'informations. Extraits pour la postérité:

L'utilisation de Write-Hostest fortement déconseillée sauf dans l'utilisation de commandes avec le Showverbe. Le Showverbe signifie explicitement "montrer à l'écran, sans autres possibilités".

ShowCette vérification n'est pas appliquée aux commandes avec le verbe.

Jeffrey Snover a un article de blog Write-Host considéré comme nocif dans lequel il affirme que Write-Host est presque toujours la mauvaise chose à faire car il interfère avec l'automatisation et fournit plus d'explications derrière le diagnostic, mais ce qui précède est un bon résumé.

Drew Noakes
la source
3

D'après mes tests, Write-Output et [Console] :: WriteLine () fonctionnent bien mieux que Write-Host.

En fonction de la quantité de texte à rédiger, cela peut être important.

Ci-dessous si le résultat de 5 tests chacun pour Write-Host, Write-Output et [Console] :: WriteLine ().

Dans mon expérience limitée, j'ai constaté que lorsque je travaillais avec n'importe quel type de données du monde réel, j'avais besoin d'abandonner les applets de commande et de passer directement aux commandes de niveau inférieur pour obtenir des performances décentes de mes scripts.

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
à M
la source
1
Write-Outputet Write-Hostservent à des fins différentes, il est donc inutile de comparer leurs performances. Oui, l'utilisation directe des types .NET et de leurs méthodes est plus rapide, mais vous manquez les fonctionnalités de niveau supérieur que les applets de commande PowerShell peuvent fournir. [Console]::WriteLine()est similaire au Write-Hostcas présent, mais ne fonctionnera pas dans toutes les circonstances, car tous les hôtes PowerShell ne sont pas des consoles .
mklement0
0

Concernant [Console] :: WriteLine () - vous devriez l'utiliser si vous allez utiliser des pipelines dans CMD (pas dans PowerShell). Supposons que vous souhaitiez que votre ps1 diffuse beaucoup de données sur stdout et un autre utilitaire pour les consommer / les transformer. Si vous utilisez Write-Host dans le script, ce sera beaucoup plus lent.

Mike Twc
la source