В обычном консольном окне , в PowerShell v3 и выше строки stderr печатаются так же, как и строки stdout .
Это желательно, потому что stderr используется многими программами не только для сообщения о подлинных ошибках, но и для всего, что является не данными , например сообщениями о состоянии .
Строки Stderr (если не перенаправлены - см. Ниже) печатаются прямо через консоль (тогда как строки stdout отправляются в выходной поток успеха PowerShell, где их можно собирать в переменную, отправляя черезконвейер или перенаправлен с >
/ >>
).
К сожалению, PowerShell ISE , даже вv5.1 , делает печать строк stderr в красный , в том же формате, что и ошибки PowerShell .
- Код Visual Studio с расширением PowerShell не имеет этой проблемы, и его стоит перейти наВ общем, учитывая, что все будущие усилия по разработке будут сосредоточены там, и учитывая, что он также работает с кроссплатформенной версией PowerShell Core .
Хорошо функционирующие консольные приложения только используют код выхода , чтобы сигнализировать об успехе (код выхода 0
) или об ошибке (любой ненулевой код выхода) .PowerShell сохраняет код завершения работы недавно запущенного консольного приложения в своей автоматической $LASTEXITCODE
переменной .
В сторону:
- Общие параметры
-ErrorAction
и -ErrorVariable
нельзя использовать с внешними программами . - Аналогично, переменная предпочтения
$ErrorActionPreference
не действует (за исключением случайно , из-за эта ошибка , начиная с PowerShell v5.1 / PowerShell Core 6.2.0-preview.4). try
/ catch
нельзя использовать для обнаружения и обработки внешнегосбой программы. - Полный обзор правил обработки сложных ошибок PowerShell см. в этом выпуске документации по GitHub .
Примечание: IВ приведенных ниже примерах используются следующие внешние команды, которые производят 1 строку stdout и 1 строку вывода stderr (обратите внимание, что перенаправление >&2
обрабатывается cmd
, а не PowerShell, поскольку оно находится внутри '...'
; используется для получения вывода stderr):
cmd /c 'echo stdout & echo stderr >&2'
Вариант, который делает командный сигнал сбой через ненулевой код выхода (exit 1
):
cmd /c 'echo stdout & echo stderr >&2 & exit 1'
Следовательно, обычно следующего должно хватить :
$stdOut = cmd /c 'echo stdout & echo stderr >&2' # std*err* will print to console
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." } # handle error
Это захватывает вывод stdout в переменную $stdout
и передает stderr вывод на консоль.
Если вы хотите собрать вывод stderr для позже и показывать их только в случае ошибка :
$stdErr = @() # initialize array for collecting stderr lines.
# Capture stdout output while collecting stderr output in $stdErr.
$stdOut = cmd /c 'echo stdout & echo stderr >&2 & exit 1' 2>&1 | Where-Object {
$fromStdErr = $_ -is [System.Management.Automation.ErrorRecord]
if ($fromStdErr) { $stdErr += $_.ToString() }
-not $fromStdErr # only output line if it came from stdout
}
# Throw an error, with the collected stderr lines included.
if ($LASTEXITCODE -ne 0) {
Throw "cmd failed with the following message(s): $stdErr"
}
Обратите внимание на перенаправление 2>&1
, которое инструктирует PowerShell отправлять строки stderr (поток 2
, поток ошибок) через конвейер (поток 1
, поток успеха)), а также.
В блоке Where-Object
$_ -is [System.Management.Automation.ErrorRecord]
используется для идентификации строк stderr , потому что PowerShell оборачивает такие строки в экземплярах этого типа.
Кроме того, вы можете собрать вывод stderr во временный файл (2>/path/to/tmpfile
), прочитать его содержимое и удалитьit.
В этом выпуске GitHub предлагается ввести возможность сбора перенаправленного вывода stderr в переменную , аналогично тому, как вы можете cmdlets собирать ошибки в переменной с помощью общего параметра
-ErrorVariable
.
Существует два предостережения :
По сути, только печать stderrстроки позже , конкретный контекст относительно вывода stdout может быть потерян.
Из-за ошибки в Windows PowerShell v5.1 / PowerShell Core 6.2.0 , $ErrorActionPreference = Stop
не должно быть эффект, потому что перенаправление 2>&1
затем вызывает ошибку завершения сценария , как только получена первая строка stderr.
Если вы хотите выборочно воздействовать на строки stderr по мере их получения :
Примечание:
По сути, как выобрабатывая строки, вы еще не будете знать, будет ли программа сообщать о неудаче или успехе в конце.
Здесь также применимо предостережение $ErrorActionPreference = 'Stop'
.
Следующий пример фильтрует строку stderr stderr1
и печатает строку stderr2
на консоли красным цветом (только текст, не как ошибка PowerShell).
$stdOut = cmd /c 'echo stdout & echo stderr1 >&2 & echo stderr2 >&2' 2>&1 |
ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) { # stderr line
$stdErrLine = $_.ToString()
switch -regex ($stdErrLine) {
'stderr1' { break } # ignore, if line contains 'stderr1'
default { Write-Host -ForegroundColor Red $stdErrLine }
}
} else { # stdout line
$_ # pass through
}
}
# Handle error.
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." }