Выход из пакета с помощью `EXIT /B X`, где X›=1, действует так, как если бы команда была успешно завершена при использовании && или || операторы между пакетными вызовами

Я пытаюсь связать серию файлов .bat, используя команду EXIT /B X для возврата успеха или неудачи и && и || для условного запуска следующего .bat (например, a.bat && b.bat).

Независимо от того, вызову ли я EXIT /B 0 или что-то еще, чтобы закончить a.bat, a.bat && b.bat впоследствии вызовет b.bat. Насколько я понимаю, EXIT /B 0 должен установить ERRORLEVEL=0, что является успехом, поэтому && следует продолжить. Противоположностью этому является то, что вызов EXIT /B 1 должен установить ERRORLEVEL=1, что является ошибкой, поэтому && должен остановиться. Что мне здесь не хватает?

Тривиальный пример:

Для непакетных команд, действующих как положено:

C:\> echo test|findstr test>NUL && echo yes
yes

C:\> echo test|findstr test>NUL || echo yes

C:\> echo test|findstr nope>NUL && echo yes

C:\> echo test|findstr nope>NUL || echo yes
yes

Использование EXIT /B всегда считает a.bat успешным:

C:\> echo @EXIT /B 0 > a.bat

C:\> a.bat && echo yes
yes

C:\> a.bat || echo yes

C:\> echo @EXIT /B 1 > a.bat

C:\> a.bat && echo yes
yes

C:\> a.bat || echo yes

Как я могу выйти из a.bat, чтобы a.bat && b.bat и a.bat || b.bat вели себя как положено?

Все команды выполняются в cmd.exe в Windows XP SP3.


person Jordan Evens    schedule 08.01.2011    source источник
comment
Я никогда раньше не видел, чтобы эти операторы использовались в пакетных файлах. Я не думаю, что ты делаешь то, что думаешь. Изменить: и я не могу найти никакой документации по этому поводу, поэтому я удивлен, что вы не видели синтаксических ошибок.   -  person Mike Caron    schedule 08.01.2011
comment
Использование этих операторов подробно описано здесь: microsoft.com/resources/documentation/windows/xp/all/proddocs/   -  person Jordan Evens    schedule 08.01.2011
comment
@JordanEvens Я получаю the page you requested cannot be found (но три голоса говорят, что это только я ...) Другое описание находится на SS64   -  person Stephan    schedule 22.08.2018
comment
Не могу сразу найти замену на сайте майкрософт, но на обратном пути есть копия оригинала: https://web.archive.org/web/20170220015700/http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspx?mfr=true   -  person Jordan Evens    schedule 22.08.2018


Ответы (4)


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

@%COMSPEC% /C exit 1 >nul

Поскольку это фактически запущенный процесс, вы получаете реальный код завершения процесса и && и || буду работать.

person Anders    schedule 08.01.2011
comment
Хотя это немного странно использовать для выхода, он обеспечивает ожидаемое поведение, когда другие вещи вызывают пакет, поэтому имеет смысл использовать это вместо того, чтобы изменять все остальное для использования вызовов. - person Jordan Evens; 09.01.2011
comment
Я немного смутился, так что это просто примечание для других, что вам буквально нужно, чтобы это была последняя строка файла. На самом деле он не выйдет из пакета, просто установит код ошибки. Вызов EXIT /B %ERRORLEVEL% сразу после этого тоже не всегда работает. Единственный надежный способ, который я нашел, — это использовать IF ERRORLEVEL 1 goto :end и иметь метку :end непосредственно перед последней строкой с %COMSPEC% /C EXIT %ERRORLEVEL%>NUL. - person Jordan Evens; 10.01.2011
comment
Может ли эта проблема быть связана с проблемой , с которой я столкнулся недавно? - person user66001; 20.01.2013

Он работает как надо при использовании call для выполнения пакетных скриптов, содержащих оператор выхода:

C:\>echo @EXIT /B 1 > a.bat

C:\>call a.bat && echo yes

C:\>call a.bat || echo yes
yes

Кстати, на ошибочно. ="nofollow noreferrer">документы Microsoft:

Вызов не действует в командной строке, если он используется вне сценария или пакетного файла.

person marapet    schedule 08.01.2011
comment
Вызов также влияет на это: set var=%%var%%‹enter›call call call echo %var% - person jeb; 09.01.2011
comment
Команда CALL была создана, чтобы исправить историческую ошибку эпохи DOS: старый интерпретатор COMMAND.COM считает, что команда пакетного файла запускается иначе, чем внешние программы (.com или .exe). Для команды пакетного файла оболочка останавливает запущенный пакетный файл и загружает новый пакет. (Думайте об этом как о exec foo.sh в оболочке Unix - старый скрипт останавливается и запускает новый.) Для решения случаев, когда пользователи/скрипты хотят продолжить выполнение после завершения нового скрипта, была введена команда CALL. Своеобразное поведение команды пакетного файла остается для совместимости. - person Explorer09; 25.04.2017
comment
Ссылка не работает. - person Peter Mortensen; 22.08.2018

Если вы используете start /wait, вы также можете использовать это в очень простом приложении Windows (написанном на C#), вызываемом пакетными файлами DOS, например так:

static class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        Environment.ExitCode = Convert.ToInt32(args[0]);
    }
}

Затем приложение может быть вызвано вашим пакетным файлом DOS и оценено результатом. то есть

c:> start /wait SetRC 1
c:> if "%errorlevel%"=="1" goto abort

ПРИМЕЧАНИЕ. /wait не требуется в пакетном файле.

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

person user2989311    schedule 13.11.2013
comment
в DOS нет команды start и %errorlevel%. Windows cmd и MS-DOS сильно отличаются - person phuclv; 22.08.2018

Я думаю, что вы получаете Errorlevel=0, потому что вы действительно выполняете a.bat (независимо от кода возврата).

Вы бы не прошли проверку, если бы a.bat не существовало. CALL — это единственный известный мне способ получить среду из a.bat.

person TheDude    schedule 28.09.2017