¿Cuál es la diferencia entre “Write-Host”, “Write-Output” o “[console] :: WriteLine”?

192

Hay varias formas diferentes de enviar mensajes. ¿Cuál es la diferencia entre la salida de efectivo a través de algo Write-Host, Write-Outputo [console]::WriteLine?

También noto que si uso:

write-host "count=" + $count

El +se incluye en la salida. ¿Porque eso? ¿No debería evaluarse la expresión para producir una sola cadena concatenada antes de que se escriba?

Scott Langham
fuente
44
Write-Outputcuando estás emitiendo resultados. Write-Hostcuando estás emitiendo información de registro. Nunca lo use [console]::writeline().
JohnL
2
@JohnL ¿por qué nunca deberíamos usar [consola] :: writeline ()?
David Klempfner
3
@Backwards_Dave Debido a que tiene Write-Host ... Ok, es posible que haya tenido la impresión de que mostraba una nueva ventana de consola (fue hace mucho tiempo). Eso no sucede, pero el hecho es que no es el idioma de PowerShell y no hay nada que puedas hacer con lo [console]::writeline("hello world")que no puedas hacer Write-Host "hello world". Otra respuesta mejor y más reciente aplicable es que se write-hostenvuelve write-informationpara que sus datos se pongan en una secuencia como write-errorpara que pueda capturarlos y usarlos en otro lugar. [console]::writeline()no hace eso
JohnL

Respuestas:

267

Write-Outputdebe usarse cuando desea enviar datos en la tubería, pero no necesariamente quiere mostrarlos en la pantalla. La tubería eventualmente lo escribirá out-defaultsi nada más lo usa primero.

Write-Host debe usarse cuando quieres hacer lo contrario.

[console]::WriteLinees esencialmente lo que Write-Hostestá haciendo detrás de escena.

Ejecute este código de demostración y examine el resultado.

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 

Deberá encerrar la operación de concatenación entre paréntesis, de modo que PowerShell procese la concatenación antes de tokenizar la lista de parámetros Write-Hosto utilice la interpolación de cadenas

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

Por cierto, mira este video de Jeffrey Snover explicando cómo funciona la tubería. Cuando comencé a aprender PowerShell, descubrí que esta era la explicación más útil de cómo funciona la canalización.

Andy Arismendi
fuente
En Azure WebJob [consola] :: WriteLine funciona pero Write-Host generará un error: el error interno de Win32 "El identificador no es válido" 0x6 se produjo al configurar los atributos de caracteres para el búfer de salida de la consola. No me preguntes por qué.
Gil Roitto
Corríjame si me equivoco, pero creo que Write-Outputes el valor predeterminado, por ejemplo, si tiene un PsObject y lo escupe en la pantalla haciendo esto $object, en realidad hará lo mismo que esto Write-Output $object. Vale la pena mencionar
Kolob Canyon
1
Hay una nueva guía: evite usar Write-Outputcuando sea posible. Consulte github.com/PoshCode/PowerShellPracticeAndStyle/issues/… > Use return solo para finalizar la ejecución. > Evitar escritura de salida (...). En cambio, cuando desee aclarar la salida, simplemente asigne la salida a una variable con un nombre relevante. y coloca una variable en una línea por sí misma para indicar una salida explícita. > Write-Output -NoEnumerate está roto en PowerShell 6 y lo ha estado durante 16 meses o más; no hay ningún plan para solucionarlo. En resumen:> NO USE la salida de escritura - NUNCA.
Jeroen Wiert Pluimers
28

Además de lo que Andy mencionó, hay otra diferencia que podría ser importante: write-host escribe directamente al host y no devuelve nada, lo que significa que no puede redirigir la salida, por ejemplo, a un archivo.

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

Ahora ejecute en PowerShell:

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

Como se ve, no puede redirigirlos a un archivo. Esto puede sorprender a alguien que no tiene cuidado.

Pero si se cambia para usar la salida de escritura en su lugar, obtendrá la redirección funcionando como se esperaba.

KFL
fuente
Es posible capturar la salida del host de escritura si usa Start-Process Powershell. \ A.ps1 -RedirectStandardOutput somefile.txt Sin embargo, hay problemas con la codificación (el archivo estará en SystemDefaultEncoding).
MKesper
16

Aquí hay otra forma de lograr el equivalente de Write-Output. Simplemente ponga su cadena entre comillas:

"count=$count"

Puede asegurarse de que esto funcione igual que Write-Output ejecutando este experimento:

"blah blah" > out.txt

Write-Output "blah blah" > out.txt

Write-Host "blah blah" > out.txt

Los dos primeros generarán "bla, bla" en out.txt, pero el tercero no.

"help Write-Output" da una pista de este comportamiento:

Este cmdlet generalmente se usa en scripts para mostrar cadenas y otros objetos en la consola. Sin embargo, dado que el comportamiento predeterminado es mostrar los objetos al final de una tubería, generalmente no es necesario usar el cmdlet.

En este caso, la cadena en sí "count = $ count" es el objeto al final de una tubería y se muestra.

FarmerBob
fuente
6

Para usos de Write-Host, PSScriptAnalyzerproduce el siguiente diagnóstico:

Evite usarlo Write-Hostporque podría no funcionar en todos los hosts, no funciona cuando no hay un host y (antes de PS 5.0) no se puede suprimir, capturar ni redirigir. En cambio, el uso Write-Output, Write-Verboseo Write-Information.

Consulte la documentación detrás de esa regla para obtener más información. Extractos para la posteridad:

Se Write-Hostdesaconseja el uso de a menos que se utilicen comandos con el Showverbo. El Showverbo explícitamente significa "mostrar en la pantalla, sin otras posibilidades".

Los comandos con el Showverbo no tienen esta verificación aplicada.

Jeffrey Snover tiene una publicación en el blog Write-Host Considerado dañino en el que afirma que Write-Host es casi siempre algo incorrecto porque interfiere con la automatización y proporciona más explicaciones detrás del diagnóstico, sin embargo, lo anterior es un buen resumen.

Drew Noakes
fuente
3

Según mis pruebas, Write-Output y [Console] :: WriteLine () funcionan mucho mejor que Write-Host.

Según la cantidad de texto que necesite escribir, esto puede ser importante.

A continuación, si el resultado de 5 prueba cada uno para Write-Host, Write-Output y [Console] :: WriteLine ().

En mi experiencia limitada, descubrí que cuando trabajo con cualquier tipo de datos del mundo real necesito abandonar los cmdlets e ir directamente a los comandos de nivel inferior para obtener un rendimiento decente de mis 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
tom
fuente
1
Write-Outputy Write-Hostsirven para diferentes propósitos, por lo que no tiene sentido comparar su desempeño. Sí, el uso directo de los tipos .NET y sus métodos es más rápido, pero se pierde las funciones de nivel superior que pueden proporcionar los cmdlets de PowerShell. [Console]::WriteLine()es similar al Write-Hostcaso en cuestión, pero no funcionará en todas las circunstancias, porque no todos los hosts de PowerShell son consolas .
mklement0
0

Con respecto a [Console] :: WriteLine (): debe usarlo si va a usar tuberías en CMD (no en powershell). Digamos que desea que su ps1 transmita una gran cantidad de datos para stdout, y alguna otra utilidad para consumirla / transformarla. Si usa Write-Host en el script, será mucho más lento.

Mike Twc
fuente