Как мне написать в стандартную ошибку в PowerShell?
У меня возникают проблемы с выяснением, как и эхо в стандартный поток ошибок и перенаправить поток ошибок исполняемого файла.
Я пришел из оболочки Bourne и Korn, которую я бы использовал;
# Write to stderr
echo "Error Message!" >&2
# Redirect stderr to file
/do/error 2>/tmp/err.msg
3 ответа
Использование Write-Error
написать в stderr. Чтобы перенаправить stderr в файл, используйте:
Write-Error "oops" 2> /temp/err.msg
или же
exe_that_writes_to_stderr.exe bogus_arg 2> /temp/err.msg
Обратите внимание, что PowerShell записывает ошибки как записи об ошибках. Если вы хотите избежать подробного вывода записей об ошибках, вы можете записать информацию об ошибке самостоятельно так:
PS> Write-Error "oops" -ev ev 2>$null
PS> $ev[0].exception
oops
-EV
является коротким (псевдоним) для -ErrorVariable
, Любые ошибки будут храниться в переменной, названной аргументом этого параметра. PowerShell по-прежнему будет сообщать об ошибке на консоль, если мы не перенаправим ошибку в $null
,
Замечания:
Этот ответ о записи в stderr с точки зрения внешнего мира, когда оттуда вызывается сценарий PowerShell; в то время как ответ написан с точки зрения оболочки Windows,
cmd.exe
это в равной степени относится и к оболочкам Unix, таким какbash
в сочетании с PowerShell Core.Напротив, изнутри Powershell, вы должны использовать
Write-Error
, как объясняется в ответе Кита Хилла.К сожалению, нет единого подхода, который бы работал как внутри PowerShell, так и извне - см. Мой ответ для обсуждения.
Чтобы добавить отличный ответ @Chris Sear:
В то время как $host.ui.WriteErrorLine
должен работать на всех хостах, он не (по умолчанию) записывает в stderr при вызове черезcmd.exe
Например, из пакетного файла.[Console]::Error.WriteLine
напротив, всегда делает.
Так что если вы хотите написать сценарий PS, который хорошо воспроизводится с точки зрения потоков вывода при вызове изcmd.exe
, используйте следующую функцию, Write-StdErr
, который использует [Console]::Error.WriteLine
в штатной PS / cmd.exe
хост (окно консоли) и $host.ui.WriteErrorLine
иначе:
<#
.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")
}
}
Дополнительная справочная информация:
Внутренне PS имеет больше, чем традиционные выходные потоки (stdout и stderr), и их количество со временем увеличилось (попробуйте Write-Warning "I'll go unheard." 3> $null
в качестве примера, и читать больше на Get-Help about_Redirection
; обратите внимание, что связанная страница еще не отражает поток6
заWrite-Information
, введенный в PSv5).
При взаимодействии с внешним миром PS долженотображать нетрадиционные выходные потоки в stdout и stderr.
Как ни странно, PowerShell по умолчанию отправляетвсе свои потоки (включаяWrite-Host
а также $host.ui.WriteErrorLine()
вывод) в стандартный вывод при вызове изcmd.exe
даже если преобразование потока ошибок PowerShell в stderr было бы логичным выбором. Это поведение действует с (по крайней мере) v2 и все еще применяется с v5.1 (и, вероятно, не изменится из-за обратной совместимости).
Вы можете проверить это с помощью следующей команды, если вы вызываете ее из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
Команда выполняет запись во все выходные потоки PS (при запуске в версии, предшествующей PSv5, вы увидите дополнительное сообщение об ошибке, относящееся к Write-Information
, который был введен в PSv5) и имеет cmd.exe
перенаправить стандартный вывод только на NUL
(то есть подавить вывод stdout; >NUL
).
Вы не увидите ничего, кроме cerr
(от [Console]::Error.WriteLine()
, который пишет напрямую в stderr) - все потоки PowerShell были отправлены на стандартный вывод.
Возможно, еще более странно, что можно перехватить поток ошибок PowerShell, но только с перенаправлением:
Если вы измените>NUL
в2>NUL
выше, это исключительно поток ошибок PowerShell и $host.ui.WriteErrorLine()
вывод, который будет подавлен; Конечно, как и при любом перенаправлении, вы можете отправить его вфайл.
(Как указано,[Console]::Error.WriteLine()]
всегда выводит в stderr, независимо от того, перенаправлен последний или нет.)
Чтобы дать более сфокусированный пример (опять же, запустить изcmd.exe
):
powershell -noprofile -command "'out'; Write-Error 'err'" 2>NUL
Выше только выходыout
-Write-Error
выходной подавлен.
Подводя итог:
Без всяких (
cmd.exe
) перенаправление илитолько перенаправление stdout (>...
или же1>...
), PowerShell отправляетвсе свои выходные потоки на стандартный вывод.С перенаправлениемstderr(
2>...
PowerShellвыборочно отправляет свой поток ошибок в stderr (независимо от того, перенаправлен ли stdout или нет).Как следствие, следующая распространенная идиомане работает должным образом:
powershell ... >data-output.txt
Это не будет, как можно было ожидать, отправлять только стандартныйвывод в файлdata-output.txt
при выводе выводаstderr на терминал; вместо этого вам придется использоватьpowershell ... >data-output.txt 2>err-output.tmp; type err-output.tmp >&2; del err-output.tmp
Отсюда следует, чтоPS знает оcmd.exe
перенаправляет и намеренно корректирует свое поведение.
(Это также видно из PS, производящего цветной вывод в cmd.exe
консоль при удалении цветовых кодов, когда вывод перенаправляется в файл.)
Если я что-то упустил и / или кто-то может предоставить обоснование такого поведения, сообщите нам об этом.
Что вы, вероятно, хотите, это:
$host.ui.WriteErrorLine('I work in any PowerShell host')
Вы также можете увидеть следующее, но предполагается, что ваш хост PS является консольным окном / устройством, поэтому я считаю его менее полезным:
[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')