Como gerar algo no PowerShell


211

Estou executando um script do PowerShell em um arquivo em lotes. O script busca uma página da web e verifica se o conteúdo da página é a sequência "OK".

O script do PowerShell retorna um nível de erro para o script em lote.

O script em lote é executado pelo ScriptFTP , um programa de automação de FTP. Se ocorrer um erro, o ScriptFTP poderá enviar a saída completa do console para o administrador por email.

No script do PowerShell, gostaria de gerar o valor de retorno do site, se não estiver "OK", para que a mensagem de erro seja incluída na saída do console e, portanto, no email de status.

Eu sou novo no PowerShell e não tenho certeza de qual função de saída usar para isso. Eu posso ver três:

  • Host de gravação
  • Saída de gravação
  • Escrever erro

Qual seria a coisa certa a ser usada para gravar no equivalente do Windows stdout?

Respostas:


197

Simplesmente produzir algo é PowerShell é uma coisa de beleza - e um dos seus maiores pontos fortes. Por exemplo, o comum Olá, Mundo! a aplicação é reduzida a uma única linha:

"Hello, World!"

Ele cria um objeto de sequência, atribui o valor acima mencionado e, sendo o último item no pipeline de comandos, chama o .toString()método e envia o resultado para STDOUT(por padrão). Uma coisa de beleza.

Os outros Write-*comandos são específicos para a saída do texto em seus fluxos associados e têm seu lugar como tal.


9
Isso não é realmente o que acontece. É uma expressão literal de string e a única coisa em seu pipeline. Assim, é equivalente a "Hello, World!" | Out-Host. Out-Hostpor outro lado, envia objetos para o host do PowerShell para exibição e sua implementação depende do host. O host do console os envia para o identificador de saída padrão (passando pelo Out-Defaultcaminho), de fato. O PowerShell ISE os exibe em seu painel de saída, no entanto, e outros hosts podem fazer outras coisas completamente.
Joey

5
Os objetos também não são convertidos cegamente em string, mas passam por um formatador que decide o que fazer com eles. É por isso que você vê Get-ChildItema saída em formato de tabela, por exemplo, e resulta com muitas propriedades (por exemplo, WMI) padrão Format-List.
Joey

120

Eu acho que neste caso você precisará de Write-Output .

Se você tem um script como

Write-Output "test1";
Write-Host "test2";
"test3";

então, se você chamar o script com saída redirecionada, algo como yourscript.ps1 > out.txt, você aparecerá test2na tela test1\ntest3\nem "out.txt".

Observe que "test3" e a linha Write-Output sempre acrescentam uma nova linha ao seu texto e não há como o PowerShell parar isso (ou seja, echo -né impossível no PowerShell com os comandos nativos). Se você deseja a funcionalidade (um tanto básica e fácil no Bash ) echo -n, consulte a resposta da samthebest .

Se um arquivo em lotes executar um comando do PowerShell, provavelmente capturará o comando Write-Output. Eu tive "longas discussões" com os administradores de sistema sobre o que deveria ser gravado no console e o que não deveria. Agora concordamos que as únicas informações se o script executado com êxito ou tiver que ser morto Write-Hostprecisam ser edificadas e tudo o que o autor do script precisa saber sobre a execução (quais itens foram atualizados, quais campos foram definidos etc.) para saída de gravação. Dessa forma, quando você envia um script ao administrador do sistema, ele pode runthescript.ps1 >someredirectedoutput.txtver facilmente na tela, se está tudo bem. Em seguida, envie o "someredirectedoutput.txt" de volta aos desenvolvedores.


9

Eu acho que o seguinte é uma boa exibição de Echo vs. Write-Host . Observe como test () realmente retorna uma matriz de entradas, e não um único int, como se poderia facilmente acreditar.

function test {
    Write-Host 123
    echo 456 # AKA 'Write-Output'
    return 789
}

$x = test

Write-Host "x of type '$($x.GetType().name)' = $x"

Write-Host "`$x[0] = $($x[0])"
Write-Host "`$x[1] = $($x[1])"

Saída do terminal acima:

123
x of type 'Object[]' = 456 789
$x[0] = 456
$x[1] = 789

Eu posso olhar para isso o dia todo ... Mas por que $x = testapenas imprimir 123e não também 456?
not2qubit

7

Você pode usar qualquer um deles em seu cenário, pois eles gravam nos fluxos padrão (saída e erro). Se você estivesse canalizando a saída para outro comando, desejaria usar o Write-Output , que terminará no Write-Host .

Este artigo descreve as diferentes opções de saída: O PowerShell O é para saída


1
Obrigado pelo link. Meu Deus, isso é complicado . Se o host de gravação for algum tipo de terminal ou função de liberação, tentarei seguir com isso e reportar.
Pekka

3
Write-Host "Found file - " + $File.FullName -ForegroundColor Magenta

Magenta pode ser um dos valores do enumerador "System.ConsoleColor" - Preto, Azul escuro, Verde escuro, Verde escuro, Ciano, Vermelho escuro, Magenta escuro, Amarelo escuro, Cinza, Cinza escuro, Azul, Verde, Ciano, Vermelho, Magenta, Amarelo, Branco.

O + $File.FullNameé opcional e mostra como colocar uma variável na string.


2

Você simplesmente não pode fazer com que o PowerShell omita essas novas linhas irritantes. Não há script ou cmdlet que faça isso.

É claro que o Write-Host é um absurdo absoluto, porque você não pode redirecionar / canalizar a partir dele! Você simplesmente tem que escrever o seu:

using System;

namespace WriteToStdout
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args != null)
            {
                Console.Write(string.Join(" ", args));
            }
        }
    }
}

Por exemplo

PS C:\> writetostdout finally I can write to stdout like echo -n
finally I can write to stdout like echo -nPS C:\>

Você poderia fazer isso no próprio PowerShell. [System.Console] :: Write ("stringy") No entanto, você não poderá redirecioná-lo de forma alguma no PowerShell.
27412 Nicholi #

1
Certamente você pode. Veja esta pergunta
Slogmeister Extraordinaire 4/16/16

1

Qual seria a coisa certa a ser usada para gravar no equivalente ao stdout no Windows?

De fato , mas infelizmente , o Windows PowerShell e o PowerShell Core a partir da v7.0 enviam todos os seus 6 (!) Fluxos de saída ao stdout quando chamados de fora , via CLI do PowerShell .

  • Veja este problema do GitHub para uma discussão sobre esse comportamento problemático, que provavelmente não será corrigido por uma questão de compatibilidade com versões anteriores.

  • Na prática, isso significa que qualquer fluxo do PowerShell para o qual você envia saída será visto como saída stdout por um chamador externo:

    • Por exemplo, se você executar o seguinte a partir cmd.exe, você verá nenhuma saída, porque o redirecionamento de stdout para NULse aplica igualmente a todos PowerShell córregos:

      • C:\>powershell -noprofile -command "Write-Error error!" >NUL
    • No entanto - curiosamente - se você redirecionar stderr , PowerShell faz enviar o seu fluxo de erro para stderr , de modo que com 2>você pode capturar a saída de erro-stream seletivamente; as seguintes saídas apenas 'hi'- a saída do fluxo de sucesso - enquanto capturam a saída do fluxo de erros no arquivo err.txt:

      • C:\>powershell -noprofile -command "'hi'; Write-Error error!" 2>err.txt

O comportamento desejável é:

  • Envie o fluxo de saída de sucesso1 do PowerShell (número ) para stdout .
  • Envie a saída de todos os outros fluxos para o stderr , que é a única opção, pois entre os processos existem apenas 2 fluxos de saída - stdout (saída padrão) para dados e stderr (erro padrão) para mensagens de erro e todos os outros tipos de mensagens - como como informações de status - que não são dados .

  • É aconselhável fazer essa distinção no seu código, mesmo que atualmente não esteja sendo respeitado .


Dentro do PowerShell :

  • Write-Hosté para saída de exibição e ignora o fluxo de saída de sucesso - como tal, sua saída não pode ser (diretamente) capturada em uma variável, nem suprimida nem redirecionada.

    • Sua intenção original era simplesmente criar feedback do usuário e criar interfaces de usuário simples, baseadas em console (saída colorida).

    • Devido à incapacidade anterior de ser capturada ou redirecionada, o PowerShell versão 5 foi criado Write-Hostpara o fluxo de informações recém-introduzido (número 6), portanto, desde então, é possível capturar e redirecionar a Write-Hostsaída.

  • Write-Errordestina-se a gravar erros sem finalização no fluxo de erros (número 2); conceitualmente, o fluxo de erros é equivalente a stderr.

  • Write-Outputgrava no fluxo de sucesso (saída) (número 1), que é conceitualmente equivalente a stdout; é o fluxo para o qual gravar dados (resultados).

    • No entanto, o uso explícito de Write-Outputraramente é necessário devido ao recurso implícito de saída do PowerShell :
      • A saída de qualquer comando ou expressão que não seja explicitamente capturada, suprimida ou redirecionada é automaticamente enviada para o fluxo de sucesso ; por exemplo, Write-Output "Honey, I'm $HOME"e "Honey, I'm $HOME"são equivalentes, com o último não apenas sendo mais conciso, mas também mais rápido.
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.