Какие внутренние команды cmd.exe очищают ERRORLEVEL до 0 при успешном завершении?

Частым методом обработки ошибок в командных сценариях Windows является использование таких вещей, как: if errorlevel 1 ... или if %errorlevel% neq 0 .... Часто требуется, чтобы код обработки ошибок сохранял ERRORLEVEL.

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

Но как насчет внутренних команд? Проблема в том, что некоторые внутренние команды очищают ERRORLEVEL до 0, когда они преуспевают, а некоторые нет. И я не могу найти документацию, определяющую, какие команды делают что.

Итак, вопрос: , какие внутренние команды очищают ERRORLEVEL до 0 при успешном завершении? Это не общий вопрос о возвращенных кодах ERRORLEVEL, но строго о результатах успеха.

Есть такие сообщения, как Что является самым простым способом для reset ERRORLEVEL до нуля? и командные файлы Windows:. bat vs .cmd?, которые дают частичные ответы. Но я никогда не видел исчерпывающего списка.

Примечание: Мне это любопытно в течение многих лет. Поэтому я, наконец, решил провести кучу экспериментов и дать окончательный ответ. Я отправляю этот Q & A, чтобы поделиться тем, что нашел.

Ответ 1

Этот ответ основан на экспериментах, которые я запускал под Windows 10. Я сомневаюсь, что существуют различия с более ранними версиями Windows, которые используют cmd.exe, но это возможно.

Также обратите внимание: этот ответ не пытается документировать результат ERRORLEVEL, когда внутренняя команда встречает ошибку (за исключением небольшого бита относительно DEL и ERASE)

Не только разница между командами, но одна команда может вести себя по-разному в зависимости от того, была ли она запущена из командной строки или внутри пакета script с расширением .bat или из пакета script с расширением .cmd.

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

  • BREAK
  • CLS
  • ECHO
  • ENDLOCAL
  • FOR: Очевидно, что команды в предложении DO могут устанавливать ERRORLEVEL, но успешное FOR с хотя бы одной итерацией не устанавливает ERRORLEVEL в 0 самостоятельно.
  • GOTO
  • IF: Очевидно, что команды, выполняемые IF, могут установить ERRORLEVEL, но успешный IF не устанавливает ERRORLEVEL в 0 самостоятельно.
  • КЛЮЧИ
  • PAUSE
  • POPD
  • RD
  • REM
  • RMDIR
  • SHIFT
  • START
  • TITLE

Следующий набор команд всегда удаляет ERRORLEVEL до 0 при успехе, независимо от контекста:

  • CD
  • CHDIR
  • COLOR
  • COPY
  • DATE
  • DEL: всегда очищает ERRORLEVEL, даже если DEL завершает работу (кроме случаев, когда выполняется без аргумента файла).
  • DIR
  • ERASE: Всегда очищает ERRORLEVEL, даже если ERASE не работает. (за исключением того, что при запуске без аргумента файла).
  • MD
  • MKDIR
  • MKLINK
  • MOVE
  • PUSHD
  • REN
  • RENAME
  • SETLOCAL
  • TIME
  • ТИП
  • VER
  • ПРОВЕРИТЬ
  • VOL

Затем появляются эти команды, которые не удаляют ERRORLEVEL при успешном выполнении, если они выданы из командной строки или внутри script с расширением .bat, но очищают ERRORLEVEL до 0, если они выпущены из script, с .cmd расширение. Подробнее см. fooobar.com/questions/13336/... и https://groups.google.com/forum/#!msg/microsoft.public.win2000.cmdprompt.admin/XHeUq8oe2wk/LIEViGNmkK0J.

  • ASSOC
  • DPATH
  • FTYPE
  • PATH
  • ПОДСКАЖИТЕ
  • SET

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

  • CALL: Если CALLed: a: procedure или batch script, то ERRORLEVEL управляется исключительно с помощью CALLed script или:. Но любой другой тип успешного CALL для команды всегда будет очищать ERRORLEVEL до 0, если команда CALLed иначе не устанавливает его.
    Пример: call echo OK.

  • EXIT: если используется без /B, то сеанс cmd.exe завершается, и больше нет ERRORLEVEL, а только код возврата cmd.exe. Очевидно, что EXIT /B 0 очищает ERRORLEVEL до 0, но EXIT /B без значения сохраняет предыдущий ERRORLEVEL.

Я считаю, что учет всех внутренних команд, если только нет недокументированной команды, которую я пропустил.

Ответ 2

Ваше описание команды CALL не завершено:

CALL: очищает ERRORLEVEL, если команда CALLed иначе не устанавливает его. Пример: call echo OK.

Проверьте этот небольшой пример:

@echo off

call :setTwo
echo Set two: %errorlevel%

call :preserve
echo Preserve: %errorlevel%

call echo Reset
echo Reset: %errorlevel%

call :subNotExists 2> NUL
echo Sub not exist: %errorlevel%

goto :EOF

:setTwo
exit /B 2

:preserve
echo Preserve
exit /B

Вывод:

Set two: 2
Preserve
Preserve: 2
Reset
Reset: 0
Sub not exist: 1

CALL описание должно сказать что-то вроде этого:

  • CALL: очищает ERRORLEVEL, если команда CALLed иначе не устанавливает его. Пример: call echo OK, но если вызываемая команда является подпрограммой, она сохраняет предыдущий ERRORLEVEL. Если вызываемая подпрограмма не существует, она устанавливает ERRORLEVEL равным 1.