В командной строке почему %ErrorLevel% не влияет на то, выполняется ли вторая команда echo после оператора &&?

Вопрос или проблема

Проблема

Оператор && не учитывает значение %ErrorLevel%. Команда, следующая за оператором, выполняется, несмотря на то, что %ErrorLevel% равен 99.

Команда

cmd /c exit 99
echo %ErrorLevel%
echo %ErrorLevel% && echo %ErrorLevel%
echo %ErrorLevel%

Вывод

99
99
99
99

Разъяснение проблемы

Насколько я понимаю, следующее верно:

  • Оператор && эквивалентен if "%ErrorLevel%" equ "0".
  • Команда Echo не изменяет %ErrorLevel%.

Устранение неполадок

Я попытался включить отложенное расширение, используя cmd /v:on, и выполнив следующую команду, но получил тот же вывод. Я протестировал следующую команду в консоли, в .bat файле и в .cmd файле.

setlocal EnableDelayedExpansion
cmd /c exit 99
echo %ErrorLevel%
echo %ErrorLevel% && echo !ErrorLevel!
echo %ErrorLevel%

Использование команды if изменяет поведение так, как я ожидаю. И замена приведенного ниже кода, чтобы заменить cmd /c exit 99 на cmd /c exit 0, изменяет вывод на 3 эха 99 вместо 4 эхов 99.

Команда

setlocal EnableDelayedExpansion
cmd /c exit 99
echo %ErrorLevel%
echo %ErrorLevel% & if "%ErrorLevel%" equ "0" echo !ErrorLevel!
echo %ErrorLevel%

Вывод

99
99
99

Ответ

Ответ wildkoala кажется правильным. Операторы && и || проверяют код выхода предыдущей команды, а не текущее значение в переменной %ErrorLevel%.

Некоторые команды не обновляют переменную %ErrorLevel%. Тем не менее, они все равно будут иметь код выхода.

Более подробно можно прочитать о различии между errorlevel и кодами выхода на ss64 здесь.

Документация часто упрощает объяснение операторов && и || как проверку, является ли %ErrorLevel% равным 0.


Как оценить код выхода команды

Вы можете использовать команду call для переменной или скрипта, который заканчивается командой, которую вы хотите оценить. Это заставит переменную %ErrorLevel% обновиться кодом выхода последней команды.

Пример

cmd /v:on

set command1=cmd /c exit 99
set command2=echo hide output^>nul

%command1% & echo !ErrorLevel!
99

%command2% & echo !ErrorLevel!
99

call %command2% & echo !ErrorLevel!
0

call %command1% & echo !ErrorLevel!
99

Оператор && только проверяет статус выхода предыдущей команды, в данном случае echo %ErrorLevel%, не %ErrorLevel% сам по себе. Даже если ваша предыдущая команда приводит к изменению %ErrorLevel%, && не будет его оценивать.

В результате, echo %ErrorLevel% && echo %ErrorLevel% выполнится, если echo %ErrorLevel% вернет код выхода 0 (что и происходит, так как она выполнена успешно). Таким образом, как вы уже выяснили, необходимо использовать оператор if вместо этого.

Ответ или решение

Проблема с оператором && и значением %ErrorLevel% в командной строке Windows

Введение

Вопрос о том, почему оператор && не учитывает значение %ErrorLevel%, вызывает много путаницы среди пользователей Windows, особенно тех, кто активно работает с командной строкой и сценариями .bat/.cmd. Данная статья подробно разъясняет данную проблему, разобравшись в механизмах работы операторов и обработки кодов возврата в Windows.

Описание проблемы

Когда вы выполняете команду, которая изменяет код возврата (например, cmd /c exit 99), вы ожидаете, что в дальнейшем код обработки ошибок будет зависеть от этого значения. Однако оператор && работает по-другому. Рассмотрим команду:

cmd /c exit 99
echo %ErrorLevel%
echo %ErrorLevel% && echo %ErrorLevel%

Вывод будет следующим:

99
99
99
99

В этом примере, несмотря на то что %ErrorLevel% равен 99, вторая команда echo %ErrorLevel% выполняется.

Причины поведения

  1. Как работает оператор &&: Оператор && выполняет следующую команду только в случае успешного завершения предыдущей команды (код возврата 0). Он проверяет код возврата непосредственно после выполнения команды, а не текущее значение переменной %ErrorLevel%. В данном случае в качестве предыдущей команды выступает echo %ErrorLevel%, которая выполняется успешно, и, следовательно, echo %ErrorLevel% выполняется вновь.

  2. Неизменяемость %ErrorLevel% для команд: Команда echo не изменяет код возврата, и она всегда завершается успешно (0). Поэтому && считает, что последующая команда может выполняться.

Пример с измененной логикой

Для правильной проверки кодов возврата следует использовать условие, которое проверяет значение %ErrorLevel%:

echo %ErrorLevel% & if "%ErrorLevel%" equ "0" echo %ErrorLevel%

Этот подход корректно обрабатывает значение кода возврата, так как if опирается на фактическое значение, а не на значение переменной.

Динамическое расширение переменных

Использование динамического расширения переменных (setlocal EnableDelayedExpansion) изменяет способ работы с переменными внутри команд, однако в данном контексте это не решает проблему.

setlocal EnableDelayedExpansion
cmd /c exit 99
echo %ErrorLevel%
echo %ErrorLevel% && echo !ErrorLevel!

Вы получите такой же результат, поскольку оператор && все равно проверяет предыдущую команду, а не переменную.

Как правильно обрабатывать коды возврата

Если вы хотите получить корректное поведение от командной строки, рекомендуется использовать команду call для вызова других команд и получения актуального значения кода возврата. Например:

set command=cmd /c exit 99
call %command% & echo !ErrorLevel!

Это гарантирует получение ожидаемого кода возврата.

Заключение

Оператор && в командной строке Windows не учитывает значение переменной %ErrorLevel% в момент выполнения команды. Он основан на кодах возврата предыдущих команд. Чтобы корректно управлять логикой выполнения команд в зависимости от кода возврата, необходимо использовать конструкции if, а также call для выполнения команд внутри контекста, требующего правильного обновления %ErrorLevel%. Это поможет избежать недоразумений и позволит более точно контролировать поведение сценариев Windows.

Оцените материал
Добавить комментарий

Капча загружается...