Как мне написать в стандартную ошибку в PowerShell? - PullRequest
38 голосов
/ 15 февраля 2011

У меня возникают проблемы с выяснением того, как отобразить стандартный поток ошибок и перенаправить поток ошибок исполняемого файла.

Я пришел из оболочки Борна и Korn shell фон, из которого я бы использовал;

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

# Redirect stderr to file
/do/error 2>/tmp/err.msg

Ответы [ 3 ]

41 голосов
/ 15 февраля 2011

Используйте 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.

31 голосов
/ 22 марта 2011

Вы, вероятно, хотите это:

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

Вы также можете увидеть следующее, но предполагается, что ваш хост PowerShell является консолью. окно / устройство, поэтому считаю его менее полезным:

[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')
28 голосов
/ 28 марта 2013

Примечание:

  • Этот ответ о записи в stderr с точки зрения внешнего мира , когда оттуда вызывается сценарий PowerShell; хотя ответ написан с точки зрения оболочки Windows , cmd.exe, он в равной степени относится к оболочкам Unix , таким как bash, в сочетании с PowerShell Core.

  • Для сравнения: из в пределах Powershell , вы должны использовать Write-Error, как объяснено в Ответ Кита Хилла .

  • К сожалению, существует нет унифицированный подход , который будет работать как от в PowerShell , так и извне - см. этот ответ моего для обсуждения.


Чтобы добавить к @ отличный ответ Криса Сира :

Хотя $host.ui.WriteErrorLine должен работать на всех хостах, (по умолчанию) не записывает в stderr при вызове через cmd.exe, например, из пакетного файла. [Console]::Error.WriteLine, напротив, всегда делает .

Итак, , если вы хотите написать сценарий PowerShell, который прекрасно воспроизводится с точки зрения потоков вывода при вызове из 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")
  }
}

Дополнительная справочная информация:

Внутренне, PowerShell имеет больше , чем традиционные выходные потоки (stdout и stderr), и их количество со временем увеличивается (попробуйте Write-Warning "I'll go unheard." 3> $null в качестве примера, и читайте больше в Get-Help about_Redirection; обратите внимание, что связанная страница еще не отражает поток 6 для Write-Information, представленный в PowerShell v5).

При взаимодействии с внешним миром PowerShell должен отображать нетрадиционные выходные потоки в stdout и stderr.

Как ни странно, PowerShell по умолчанию отправляет все своих потоков (включая выходные данные Write-Host и $host.ui.WriteErrorLine()) на stdout при вызове из 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

Команда выполняет запись во все выходные потоки PowerShell (при запуске в версии, предшествующей PowerShell-v5, вы увидите дополнительное сообщение об ошибке, относящееся к Write-Information, которое было представлено в PowerShell v5), и имеет cmd.exe перенаправить только стандартный вывод на NUL (т. е. подавить вывод стандартный вывод; >NUL).

Вы увидите вывод no , кроме cerr (из [Console]::Error.WriteLine(), который записывает напрямую в stderr) - все потоки PowerShell были отправлены в stdout.

Возможно, еще более странно, что является возможным для захвата потока ошибок 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) или только с a stdout с перенаправлением (>... или 1>...) PowerShell отправляет все его выходные потоки в стандартный вывод .

  • При перенаправлении stderr (2>...) PowerShell выборочно отправляет свой поток ошибок в stderr (независимо ото том, перенаправлен ли стандартный вывод или нет).

  • Как следствие, следующая общая идиома не работает должным образом:
    powershell ... >data-output.txt Это будетнет, как и следовало ожидать, отправлять только stdout в файл data-output.txt во время печати stderr вывода на терминал;вместо этого вам придется использовать
    powershell ... >data-output.txt 2>err-output.tmp; type err-output.tmp >&2; del err-output.tmp

Из этого следует, что PowerShell знает о перенаправлениях cmd.exe и намеренно корректирует свое поведение .(Это также видно из того, что PowerShell создает цветной вывод в cmd.exe консоли , одновременно обрабатывая цветовые коды, когда вывод перенаправляется в файл.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...