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

вступление

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

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

Вопрос

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

Моя попытка

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

if not errorlevel 0 (
    echo error level was nonzero
)

1 ответ

Решение

Извините, ваша попытка даже не близка. 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)

Примечание. Я отредактировал свой ответ, чтобы явно очистить любое пользовательское значение уровня ошибки после прочтения комментария Джои к связанному ответу в вопросе. Пользовательский уровень ошибки может маскировать динамическое значение, к которому мы пытаемся получить доступ. Но это работает только если ваш скрипт имеет .bat расширение. Скрипты с .cmd Расширение установит ваш ERRORLEVEL в 0, если вы установите или очистите переменную! Что еще хуже, XP установит ERRORLEVEL в 1, если вы попытаетесь отменить определение несуществующей переменной. Вот почему я сначала явно определяю переменную ERRORLEVEL, прежде чем пытаюсь ее очистить!

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

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)
)


Вот, наконец, "окончательный" тест на ненулевой уровень ошибки, который должен работать при любых обстоятельствах:-)

(
  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
)


Последний вопрос:

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

Другие вопросы по тегам