Comment puis-je écrire à l'erreur standard dans PowerShell?

j'ai du mal à comprendre comment faire écho au flux d'erreur standard et rediriger le flux d'erreur d'un exécutable.

je viens d'un Bourne shell et Korn shell arrière-plan, dont je voudrais utiliser;

# Write to stderr
echo "Error Message!" >&2

# Redirect stderr to file
/do/error 2>/tmp/err.msg
35
demandé sur Peter Mortensen 2011-02-15 01:45:21

3 réponses

Utiliser Write-Error pour écrire à stderr. Pour rediriger stderr à l'utilisation du fichier:

 Write-Error "oops" 2> /temp/err.msg

ou

 exe_that_writes_to_stderr.exe bogus_arg 2> /temp/err.msg

notez que PowerShell écrit les erreurs comme des enregistrements d'erreurs. Si vous voulez éviter la sortie détaillée des enregistrements d'erreur, vous pouvez écrire l'erreur info vous-même comme ceci:

PS> Write-Error "oops" -ev ev 2>$null
PS> $ev[0].exception
oops

-EV est court (un pseudonyme) pour -ErrorVariable. Toute erreur sera stockée dans la variable nommée par l'argument de ce paramètre. PowerShell signalera quand même l'erreur à la console, sauf si nous rediriger l'erreur $null.

37
répondu Keith Hill 2016-03-24 22:27:11

ce que vous voulez probablement est ceci:

$host.ui.WriteErrorLine('I work in any PowerShell host')

vous pouvez aussi voir ce qui suit, mais il suppose que votre hôte PS est une console fenêtre/de l'appareil, donc je considère qu'il est moins utile:

[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')
30
répondu Chris Sears 2014-06-03 15:28:21

Remarque:

  • Cette réponse est sur le écrire à stderr du point de vue de la monde extérieur quand un script PowerShell est appelé de là; alors que la réponse est écrite du point de vue de Windows shell, cmd.exe, il s'applique également à Unix coques, telles que bash lorsqu'il est combiné avec le noyau PowerShell.

  • par contraste,à partir de à l'intérieur de Powershell, vous devez utiliser Write-Error, comme expliqué dans la réponse de Keith Hill.

  • malheureusement, il y a aucun unifié approche à partir de à l'intérieur de PowerShell et à partir de l'extérieur - voir cette réponse de moi pour une discussion.


ajouter @Chris Sear est génial répondre à:

$host.ui.WriteErrorLine devrait fonctionner dans tous les hôtes, il n'a pas (par défaut) d'écrire sur la sortie stderr lorsqu'il est appelé par cmd.exe, comme à partir d'un fichier de commandes. [Console]::Error.WriteLine par contre, toujours.

si vous voulez écrire un script PS qui joue bien en termes de flux de sortie lorsqu'il est invoqué à partir de cmd.exe, utilisez la fonction suivante, Write-StdErr, qui utilise [Console]::Error.WriteLine dans l'ordinaire de PS / cmd.exe hôte (fenêtre de la console) et $host.ui.WriteErrorLine sinon:

<#
.SYNOPSIS
Writes text to stderr when running in a regular console window,
to the host''s error stream otherwise.

.DESCRIPTION
Writing to true stderr allows you to write a well-behaved CLI
as a PS script that can be invoked from a batch file, for instance.

Note that PS by default sends ALL its streams to *stdout* when invoked from 
cmd.exe.

This function acts similarly to Write-Host in that it simply calls
.ToString() on its input; to get the default output format, invoke
it via a pipeline and precede with Out-String.

#> 
function Write-StdErr {
  param ([PSObject] $InputObject)
  $outFunc = if ($Host.Name -eq 'ConsoleHost') { 
    [Console]::Error.WriteLine
  } else {
    $host.ui.WriteErrorLine
  }
  if ($InputObject) {
    [void] $outFunc.Invoke($InputObject.ToString())
  } else {
    [string[]] $lines = @()
    $Input | % { $lines += $_.ToString() }
    [void] $outFunc.Invoke($lines -join "`r`n")
  }
}

Informations générales facultatives:

interne, PS a plus que les flux de sortie traditionnels (stdout et stderr), et leur nombre a augmenté avec le temps (essayez Write-Warning "I'll go unheard." 3> $null comme exemple, et en lire plus à Get-Help about_Redirection; a noter que la page n'a pas encore compte de flux 6Write-Information, introduit dans PSv5).

lors de l'interfaçage avec le monde extérieur, PS doit carte les flux de sortie non traditionnels vers stdout et stderr.

Étrangement, cependant, PowerShell par défaut envoie ses flux (y compris Write-Host et $host.ui.WriteErrorLine() sortie) stdout lorsqu'elle est invoquée à partir de cmd.exe, même si mapper le flux d'erreurs de PowerShell à stderr serait le choix logique. Ce comportement est en vigueur depuis (au moins) v2 et s'applique toujours à partir de v5.1 (et ne changera probablement pas pour des raisons de rétrocompatibilité).

Vous pouvez le vérifier avec la commande suivante si vous l'invoquez de cmd.exe:

powershell -noprofile -command "'out'; Write-Error 'err'; Write-Warning 'warn'; Write-Verbose -Verbose 'verbose'; $DebugPreference='Continue'; write-debug 'debug'; $InformationPreference='Continue'; Write-Information 'info'; Write-Host 'host'; $host.ui.WriteErrorLine('uierr'); [Console]::Error.WriteLine('cerr')" >NUL

la commande écrit à tous les flux de sortie PS (lorsque vous exécutez sur une version pré-PSv5, vous verrez un message d'erreur supplémentaire relatif à Write-Information, qui a été introduit dans PSv5) et a cmd.exe redirection stdout seulementNUL (i.e.,supprimer sortie stdout; >NUL).

Vous allez voir aucun sortie à l'exception de cerr ([Console]::Error.WriteLine(), qui écrit directement à stderr) - tous les flux de PowerShell ont été envoyés à stdout.

peut-être encore plus étrangement, il permet de capturer des PowerShell du flux d'erreur, mais seulement avec une redirection:

si vous changez >NUL2>NUL ci-dessus, il est exclusivement PowerShell flux d'erreur et $host.ui.WriteErrorLine() sortie qui sera supprimée; bien sûr, comme avec n'importe quel de redirection, vous pouvez l'envoyer à un le fichier.

(Comme l'a dit, [Console]::Error.WriteLine()]toujours sorties vers stderr, que cette dernière soit redirigée ou non.)

pour donner un exemple plus précis (encore une fois, exécutez cmd.exe):

powershell -noprofile -command "'out'; Write-Error 'err'" 2>NUL

Le dessus de sorties out -Write-Error's la sortie est réprimer.

Pour résumer:

  • Sans (cmd.exe) redirection ou avec stdout redirection (>... ou 1>...), PowerShell envoie ses flux de sortie vers stdout.

  • Avec un stderr redirection (2>...), PowerShell sélectivement envoie ses flux d'erreur pour stderr (que stdout soit redirigé ou non).

  • comme corollaire, l'idiome commun suivant Fait fonctionne comme prévu:

    powershell ... >data-output.txt

    Comme on pouvait s'y attendre, cela n'enverra pas seulement stdout dans le fichier data-output.txt lors de l'impression d' stderr sortie vers le terminal; au lieu de cela, vous devez utilisez

    powershell ... >data-output.txt 2>err-output.tmp; type err-output.tmp >&2; del err-output.tmp

Il s'ensuit que PS est conscient de cmd.exeles redirections et ajuste son comportement intentionnellement.

(Ceci est également évident à partir de PS produisant couleur sortie cmd.exe console lors de la suppression des codes de couleur lorsque la sortie est redirigée vers un fichier.)

si je manque quelque chose et/ou quelqu'un peut fournir une justification de conception pour ce comportement, s'il vous plaît laissez-nous savoir.

24
répondu mklement0 2018-05-14 17:10:21