J'ai du mal à comprendre comment à la fois 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 background, dont j'utiliserais;
# Write to stderr
echo "Error Message!" >&2
# Redirect stderr to file
/do/error 2>/tmp/err.msg
Utilisation Write-Error
pour écrire à stderr. Pour rediriger stderr vers un fichier, utilisez:
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 sous forme d'enregistrements d'erreur. Si vous voulez éviter la sortie détaillée des enregistrements d'erreur, vous pouvez écrire les informations d'erreur vous-même comme ceci:
PS> Write-Error "oops" -ev ev 2>$null
PS> $ev[0].exception
oops
-EV
est court (un alias) pour -ErrorVariable
. Toutes les erreurs seront stockées dans la variable nommée par l'argument de ce paramètre. PowerShell signalera toujours l'erreur à la console, sauf si nous redirigeons l'erreur vers $null
.
Vous voulez probablement ceci:
$Host.ui.WriteErrorLine('I work in any PowerShell Host')
Vous pouvez également voir ce qui suit, mais cela suppose que votre hôte PowerShell est une fenêtre/périphérique de console, donc je considère que c'est moins utile:
[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')
Remarque:
Cette réponse concerne l'écriture sur stderr du point de vue du monde extérieur lorsqu'un script PowerShell est appelé à partir de là; tandis que la réponse est écrite du point de vue du shell Windows, cmd.exe
, elle s'applique également aux shell Unix tels que bash
lorsqu'il est combiné avec PowerShell Core.
En revanche, from within Powershell , vous devez utiliser Write-Error
, Comme expliqué dans Réponse de Keith Hill .
Malheureusement, il n'y a pas unifié approche qui fonctionnera des deux à l'intérieur PowerShell et de l'extérieur - voir cette réponse à moi pour une discussion.
Pour ajouter à @ la grande réponse de Chris Sear :
Alors que $Host.ui.WriteErrorLine
Devrait fonctionner sur tous les hôtes, il n'écrit pas (par défaut) sur stderr lorsqu'il est appelé via cmd.exe
, comme à partir d'un fichier de commandes. [Console]::Error.WriteLine
, En revanche, toujours fait .
Donc si vous voulez écrire un script PowerShell qui joue bien en termes de flux de sortie lorsqu'il est invoqué depuis cmd.exe
, utilisez la fonction suivante, Write-StdErr
, Qui utilise [Console]::Error.WriteLine
Dans la fenêtre de console standard de l'hôte PS/cmd.exe
(), 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")
}
}
En interne, PowerShell a plus que les flux de sortie traditionnels (stdout et stderr), et leur nombre a augmenté au fil du temps (essayez Write-Warning "I'll go unheard." 3> $null
Comme exemple, et lisez la suite sur - Get-Help about_Redirection
; notez que la page liée ne reflète pas encore le flux 6
Pour Write-Information
, introduit dans PowerShell v5).
Lors de l'interface avec le monde extérieur, PowerShell doit mapper les flux de sortie non traditionnels vers stdout et stderr.
Étrangement, cependant, PowerShell envoie par défaut tous ses flux (y compris Write-Host
Et $Host.ui.WriteErrorLine()
output) vers stdout lorsqu'il est appelé à partir de cmd.exe
, même si le mappage du flux d'erreurs de PowerShell à stderr serait le choix logique. Ce comportement est en vigueur depuis (au moins) la v2 et s'applique toujours à partir de la v5.1 (et ne changera probablement pas pour des raisons de compatibilité descendante).
Vous pouvez le vérifier avec la commande suivante, si vous l'appelez depuis 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 dans tous les flux de sortie PowerShell (lorsque vous exécutez sur une version antérieure à PowerShell-v5, vous verrez un message d'erreur supplémentaire concernant Write-Information
, Qui a été introduit dans PowerShell v5) et contient cmd.exe
Redirige stdout uniquement vers NUL
(c'est-à-dire supprime sortie stdout; >NUL
).
Vous verrez non sortie sauf cerr
(de [Console]::Error.WriteLine()
, qui écrit directement sur stderr) - tous les flux de PowerShell ont été envoyés à stdout.
Peut-être encore plus étrangement, il est possible de capturer le flux d'erreur de PowerShell, mais uniquement avec une redirection:
Si vous remplacez >NUL
Par 2>NUL
Ci-dessus, c'est exclusivement la sortie flux d'erreur et $Host.ui.WriteErrorLine()
de PowerShell qui sera supprimée; bien sûr, comme pour toute redirection, vous pouvez également l'envoyer dans un fichier -. (Comme indiqué, [Console]::Error.WriteLine()]
toujours renvoie à stderr, que ce dernier soit redirigé ou non.)
Pour donner un exemple plus ciblé (encore une fois, exécutez à partir de cmd.exe
):
powershell -noprofile -command "'out'; Write-Error 'err'" 2>NUL
La sortie ci-dessus ne produit que la sortie de out
- Write-Error
Est supprimée.
Pour résumer :
Sans aucune redirection (cmd.exe
) Ou avec seulement a stdout redirection (>...
Ou 1>...
) , PowerShell envoie tous ses flux de sortie à stdout.
Avec une redirection stderr (2>...
), PowerShell sélectivement envoie son flux d'erreur à stderr (indépendamment du fait que stdout soit également redirigé ou non).
En corollaire, l'idiome commun suivant ne fonctionne pas pas comme prévu:powershell ... >data-output.txt
Ceci, comme on pourrait s'y attendre, n'enverra que stdout dans le fichier data-output.txt
Lors de l'impression stderr sortie vers le terminal; à la place, vous devez utiliserpowershell ... >data-output.txt 2>err-output.tmp; type err-output.tmp >&2; del err-output.tmp
Il s'ensuit que PowerShell est au courant des redirections de cmd.exe
Et ajuste son comportement intentionnellement. (Cela est également évident lorsque PowerShell produit coloré sortie dans la cmd.exe
console tout en supprimant les codes de couleur lorsque la sortie est redirigée vers un fichier. )