Вопрос по batch-file, windows – Надежный способ проверки ненулевого (ошибочного) кода возврата в командном файле Windows

18
Intro

Существует множество советов по работе с кодами возврата в пакетных файлах (с использованием механизма ERROLEVEL), например,

Get error code from within a batch file ERRORLEVEL inside IF

Некоторый совет должен сделатьif errorlevel 1 goto somethingbadв то время как другие рекомендуют использовать %ERRORLEVEL% переменная и использование==, EQU, LSSи т. д. Похоже, что проблемы внутриIF заявления и тому подобное, так что тогда задержка расширения поощряется, но, похоже, она имеет свои причуды.

Question

Что является надежным (то есть надежным, так что он будет работать практически на любой системе с почти любым кодом возврата), чтобы узнать, если это плохо (nonzero) код был возвращен?

My attempt

Для базового использования следующее, кажется, работает нормально, чтобы поймать любой ненулевой код возврата:

if not errorlevel 0 (
    echo error level was nonzero
)

Ваш Ответ

1   ответ
40

if not errorlevel 0 Истинно, только если уровень ошибки отрицателен.

Если вы знаете, что уровень ошибки никогда не будет отрицательным, то

if errorlevel 1 (echo error level is greater than 0)

Если вы должны учитывать отрицательный уровень ошибки и не входите в блок кода, заключенный в скобки, то

set "errorlevel=1"
set "errorlevel="
if %errorlevel% neq 0 (echo error level is non-zero)

Note - I edited my answer to explicitly clear any user defined errorlevel value after reading Joey's comment to the linked answer in the question. A user defined errorlevel can mask the dynamic value that we are trying to access. But this only works if your script has a .bat extension. Scripts with .cmd extension will set your ERRORLEVEL to 0 if you set or clear a variable! To make matters worse, XP will set ERRORLEVEL to 1 if you attempt to undefine a variable that does not exist. That is why I first explicitly define an ERRORLEVEL variable before I attempt to clear it!

Если вы находитесь в заключенном в скобки блоке кода, вы должны использовать отложенное расширение, чтобы получить текущее значение

setlocal enableDelayedExpansion
(
  SomeCommandThatMightGenerateAnError
  set "errorlevel=1"
  set "errorlevel="
  if !errorlevel! neq 0 (echo error level is non-zero)
)

Но иногда вы не хотите, чтобы отложенное расширение было включено. Не все потеряно, если вы хотите проверить уровень ошибки сразу после выполнения команды.

(
  SomeCommandThatMightGenerateAnError && (echo Success, no error) || (echo There was an error)
)

Если вам абсолютно необходимо проверить динамическое значение ERRORLEVEL без использования отложенного расширения внутри блока в скобках, тогда работает следующее. Но он имеет код обработки ошибок в двух местах.

(
  SomeCommandThatMightGenerateAnError
  if errorlevel 1 (echo errorlevel is non-zero) else if not errorlevel 0 (echo errorlevel is non-zero)
)


Here, at long last, is the "ultimate" test for non-zero errrolevel that should work under any circumstances :-)

(
  SomeCommandThatMightGenerateAnError
  set foundErr=1
  if errorlevel 0 if not errorlevel 1 set "foundErr="
  if defined foundErr echo errorlevel is non-zero
)

Это может даже быть преобразовано в макрос для простоты использования:

set "ifErr=set foundErr=1&(if errorlevel 0 if not errorlevel 1 set foundErr=)&if defined foundErr"
(
  SomeCommandThatMightGenerateAnError
  %ifErr% echo errorlevel is non-zero
)

Макрос поддерживает круглые скобки и ELSE просто отлично:

%ifErr% (
  echo errorlevel is non-zero
) else (
  echo errorlevel is zero
)


One last issue:

Перенаправление ввода и / или вывода может завершиться ошибкой по ряду причин. Но ошибки перенаправления делаютnot установить уровень ошибки, если только|| оператор используется. УвидетьПеренаправление файлов в Windows и% errorlevel% для дополнительной информации. Таким образом, можно утверждать, что не существует надежного способа проверки ошибок с помощью уровня ошибок. Самый надежный метод (но все же не безошибочный)|| оператор.

Стоит отметить, что уровень ошибкиnot an environment variable.
РЕДАКТИРОВАТЬ 2016-06-03: Я изменил код, чтобы очистить любой определенный пользователем ERRORLEVEL, чтобы учесть поведение XP, которое устанавливает ERRORLEVEL в 1, если вы пытаетесь отменить определение несуществующей переменной.
@NickWestgate - Да, ERRORLEVEL - это одна из многих "псевдо" или "динамический" переменные. Я определил и задокументировал три класса «динамического» переменные вstackoverflow.com/a/20169219/1012053и в этом посте я ссылаюсь на тот же блог Раймонда Чена.

Похожие вопросы