Qual é a diferença entre "Write-Host", "Write-Output" ou "[console] :: WriteLine"?


192

Existem várias maneiras diferentes de enviar mensagens. Qual é a diferença efectiva entre a saída de algo via Write-Host, Write-Outputou [console]::WriteLine?

Percebo também que se eu usar:

write-host "count=" + $count

O +é incluído na saída. Por que isso? A expressão não deve ser avaliada para produzir uma única sequência concatenada antes de ser gravada?


4
Write-Outputquando você está emitindo resultados. Write-Hostquando você estiver emitindo informações de log. Nunca use [console]::writeline().
precisa saber é

2
@JohnL Por que nunca devemos usar [console] :: writeline ()?
David Klempfner 14/10

3
@ Backwards_Dave Porque você tem o Host de Gravação .... Ok, posso ter a impressão de que ele mostrou uma nova janela do console (isso foi há muito tempo). Isso não acontece, mas o fato é que não é o idioma do PowerShell e não há nada que você possa fazer com o [console]::writeline("hello world")que não possa fazer Write-Host "hello world". Outra, melhor, mais recentemente resposta aplicável é o write-hostsegredo write-informationpara que seus dados é colocado em um córrego como write-errorassim você pode capturá-lo e usá-lo em outro lugar. [console]::writeline()não faz isso
johnl

Respostas:


267

Write-Outputdeve ser usado quando você deseja enviar dados na linha de tubulação, mas não necessariamente deseja exibi-los na tela. O pipeline acabará gravando-o out-defaultse nada mais o usar primeiro.

Write-Host deve ser usado quando você quiser fazer o oposto.

[console]::WriteLineé essencialmente o que Write-Hostestá fazendo nos bastidores.

Execute este código de demonstração e examine o 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 

Você precisará colocar a operação de concatenação entre parênteses, para que o PowerShell processe a concatenação antes de tokenizar a lista de parâmetros Write-Hostou usar a interpolação de cadeias

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

BTW - Assista a este vídeo de Jeffrey Snover explicando como o pipeline funciona. Quando comecei a aprender o PowerShell, descobri que essa é a explicação mais útil de como o pipeline funciona.


Em um WebJob do Azure [console] :: WriteLine funciona, mas o Write-Host resultará em um erro: O erro interno do Win32 "O identificador é inválido" 0x6 ocorreu ao definir atributos de caractere para o buffer de saída do console. Não me pergunte o porquê.
Gil Roitto 3/11

Me corrija se eu estiver errado, mas acredito que Write-Outputseja o padrão, por exemplo, se você tiver um PsObject e cuspir na tela fazendo isso, $objectele fará a mesma coisa Write-Output $object. Pode valer a pena mencionar
Kolob Canyon

1
Há novas orientações: evite usar Write-Outputquando possível. Consulte github.com/PoshCode/PowerShellPracticeAndStyle/issues/… > Use retorno somente para finalizar a execução. > Evite saída de gravação (...). Em vez disso, quando quiser tornar a saída mais clara, apenas atribua a saída a uma variável com nome relevante. e coloque essa variável em uma linha por si só para sinalizar saída explícita. > Write-Output -NoEnumerate está quebrado no PowerShell 6 e dura 16 meses ou mais - não há plano para corrigi-lo. Em resumo:> NÃO USE Write-Output - NUNCA.
Jeroen Wiert Pluimers 05/03/19

28

Além do que Andy mencionou, há outra diferença que pode ser importante - o write-host grava diretamente no host e não retorna nada, o que significa que você não pode redirecionar a saída, por exemplo, para um arquivo.

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

Agora execute no PowerShell:

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

Como visto, você não pode redirecioná-los para um arquivo. Talvez isso seja surpreendente para alguém que não é cuidadoso.

Mas se você alternar para usar a saída de gravação, o redirecionamento funcionará conforme o esperado.


É possível capturar a saída do host de gravação se você usar o PowerShell de processo de inicialização. \ A.ps1 -RedirectStandardOutput somefile.txt Porém, há problemas com a codificação (o arquivo estará em SystemDefaultEncoding).
MKesper

16

Aqui está outra maneira de obter o equivalente a Write-Output. Basta colocar sua string entre aspas:

"count=$count"

Você pode garantir que isso funcione da mesma forma que a saída de gravação executando esta experiência:

"blah blah" > out.txt

Write-Output "blah blah" > out.txt

Write-Host "blah blah" > out.txt

Os dois primeiros exibirão "blá-blá" em out.txt, mas o terceiro não.

"help Write-Output" fornece uma dica desse comportamento:

Esse cmdlet geralmente é usado em scripts para exibir seqüências de caracteres e outros objetos no console. No entanto, como o comportamento padrão é exibir os objetos no final de um pipeline, geralmente não é necessário usar o cmdlet.

Nesse caso, a própria sequência "count = $ count" é o objeto no final de um pipeline e é exibida.


6

Para usos de Write-Host, PSScriptAnalyzerproduz o seguinte diagnóstico:

Evite usar, Write-Hostpois pode não funcionar em todos os hosts, não funciona quando não há host e (antes do PS 5.0) não pode ser suprimido, capturado ou redirecionado. Em vez disso, o uso Write-Output, Write-Verboseou Write-Information.

Consulte a documentação por trás dessa regra para obter mais informações. Trechos para a posteridade:

O uso de Write-Hosté muito desencorajado, a menos que seja usado com o Showverbo. O Showverbo significa explicitamente "mostrar na tela, sem outras possibilidades".

Os comandos com o Showverbo não têm essa verificação aplicada.

Jeffrey Snover tem uma postagem no blog Considerada prejudicial para o host de gravação, na qual afirma que host de gravação é quase sempre a coisa errada a se fazer, pois interfere na automação e fornece mais explicações por trás do diagnóstico, no entanto, o exposto acima é um bom resumo.


3

No meu teste, Write-Output e [Console] :: WriteLine () têm um desempenho muito melhor que o Write-Host.

Dependendo da quantidade de texto que você precisa escrever, isso pode ser importante.

Abaixo, se o resultado de 5 testes cada um para Write-Host, Write-Output e [Console] :: WriteLine ().

Na minha experiência limitada, descobri que, ao trabalhar com qualquer tipo de dados do mundo real, preciso abandonar os cmdlets e ir direto para os comandos de nível inferior para obter um desempenho decente dos meus 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

1
Write-Outpute Write-Hostservem a propósitos diferentes; portanto, não faz sentido comparar o desempenho deles. Sim, o uso direto dos tipos .NET e seus métodos é mais rápido, mas você perde os recursos de nível superior que os cmdlets do PowerShell podem fornecer. [Console]::WriteLine()é semelhante ao Write-Hostcaso em questão, mas não funcionará em todas as circunstâncias, porque nem todos os hosts do PowerShell são consoles .
mklement0

0

Em relação ao [Console] :: WriteLine () - você deve usá-lo se quiser usar pipelines no CMD (não no PowerShell). Digamos que você queira que seu ps1 transmita muitos dados para o stdout e algum outro utilitário para consumi-los / transformá-los. Se você usar Write-Host no script, será muito mais lento.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.