Я запускаю программу и хочу узнать, каков ее код возврата (поскольку она возвращает разные коды в зависимости от разных ошибок).
Я знаю, что в Bash я могу сделать это, запустив
echo $?
Что мне делать при использовании cmd.exe в Windows?
Погуглил "Win8 Как получить приглашение CMD для отображения статуса выхода", как мы можем это сделать в Linux. Это был лучший выбор, и он точен.
Вы можете быстро увидеть, какое приложение возвращает: app.exe & echo %errorlevel%





Переменная псевдо-среды с именем errorlevel хранит код выхода:
echo Exit Code is %errorlevel%
Также команда if имеет особый синтаксис:
if errorlevel
Подробнее см. if /?.
@echo off
my_nify_exe.exe
if errorlevel 1 (
echo Failure Reason Given is %errorlevel%
exit /b %errorlevel%
)
Предупреждение: если вы установите имя переменной среды errorlevel, %errorlevel% вернет это значение, а не код выхода. Используйте (set errorlevel=), чтобы очистить переменную среды, разрешив доступ к истинному значению errorlevel через переменную среды %errorlevel%.
Если вы запускаете непосредственно из командной строки Windows и всегда видите возвращаемый 0, см. Ответ Гэри: stackoverflow.com/a/11476681/31629
Также, если вы используете PowerShell, вы можете использовать echo Exit Code is $LastExitCode
Примечание. «Errorlevel 1» истинно, если errorlevel> = 1. Таким образом, «errorlevel 0» будет соответствовать всему. Видишь ли, если /?". Вместо этого вы можете использовать «if% ERRORLEVEL% EQU 0 (..)».
Обнаружены случаи, когда %ERRORLEVEL% равен 0, даже если произошла ошибка. Произошло при проверке %ERRORLEVEL% в cmd файле. Попытка start /wait не сработала. Единственное, что сработало - это if errorlevel 1 (...)
Дружественный совет:% ErrorLevel% - это переменная оболочки, а не переменная среды, и она также возвращает string, а не int, что означает, что вы не можете эффективно использовать EQ / NEQ.
Интересно, можно ли это поместить в командную строку, как в bash?
Используйте встроенную переменную ERRORLEVEL:
echo %ERRORLEVEL%
Но будьте осторожны, если приложение определило переменную среды с именем ERRORLEVEL!
Это не фактическая переменная среды (что, очевидно, почему она перестает работать, если существует является, переменная с таким именем).
@SteelBrain: в PowerShell он называется $LastExitCode.
Он может работать некорректно при использовании программы, которая не подключена к консоли, потому что это приложение все еще может работать, пока вы думаете, что у вас есть код выхода. Решение сделать это на C++ выглядит следующим образом:
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include "tchar.h"
#include "stdio.h"
#include "shellapi.h"
int _tmain( int argc, TCHAR *argv[] )
{
CString cmdline(GetCommandLineW());
cmdline.TrimLeft('\"');
CString self(argv[0]);
self.Trim('\"');
CString args = cmdline.Mid(self.GetLength()+1);
args.TrimLeft(_T("\" "));
printf("Arguments passed: '%ws'\n",args);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if ( argc < 2 )
{
printf("Usage: %s arg1,arg2....\n", argv[0]);
return -1;
}
CString strCmd(args);
// Start the child process.
if ( !CreateProcess( NULL, // No module name (use command line)
(LPTSTR)(strCmd.GetString()), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d)\n", GetLastError() );
return GetLastError();
}
else
printf( "Waiting for \"%ws\" to exit.....\n", strCmd );
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
int result = -1;
if (!GetExitCodeProcess(pi.hProcess,(LPDWORD)&result))
{
printf("GetExitCodeProcess() failed (%d)\n", GetLastError() );
}
else
printf("The exit code for '%ws' is %d\n",(LPTSTR)(strCmd.GetString()), result );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return result;
}
В некоторых конфигурациях вы должны добавить #include <atlstr.h>, чтобы тип CString был преобразован.
Тестирование ErrorLevel работает для приложений приставка, но, как намекает по dmihailescu, это не сработает, если вы пытаетесь запустить приложение оконный (например, на основе Win32) из командной строки. Оконное приложение будет работать в фоновом режиме, и управление немедленно вернется в командную строку (скорее всего, с нулевым значением ErrorLevel, что указывает на успешное выполнение процесса созданный). Когда оконное приложение в конце концов завершает работу, его статус выхода теряется.
Однако вместо использования консольного средства запуска C++, упомянутого в другом месте, более простой альтернативой является запуск оконного приложения с помощью команды START /WAIT в командной строке. Это запустит оконное приложение, дождется его выхода, а затем вернет управление в командную строку со статусом выхода процесса, установленным в ErrorLevel.
start /wait something.exe
echo %errorlevel%
Хорошо поймал. Я не знал об этой команде. Я только что видел, как работает> запуск / ожидание notepad.exe
Другая причина, по которой он может не работать (всегда нулевой), - это когда он находится внутри if или for. Рассмотрите возможность использования !errorlevel! вместо описано в этом ответе.
Если вы хотите точно сопоставить код ошибки (например, равен 0), используйте это:
@echo off
my_nify_exe.exe
if %ERRORLEVEL% EQU 0 (
echo Success
) else (
echo Failure Reason Given is %errorlevel%
exit /b %errorlevel%
)
if errorlevel 0 соответствует errorlevel> = 0. См. if /?.
Это чувствительно к регистру?
Нет. Vars, команды (включая «if») и «equ» работают в любом случае.
В какой-то момент мне нужно было точно передать события журнала из Cygwin в журнал событий Windows. Я хотел, чтобы сообщения в WEVL были настраиваемыми, имели правильный код выхода, детали, приоритеты, сообщение и т. д. Поэтому я создал небольшой сценарий Bash, чтобы позаботиться об этом. Вот он на GitHub, logit.sh.
Некоторые отрывки:
usage: logit.sh [-h] [-p] [-i=n] [-s] <description>
example: logit.sh -p error -i 501 -s myscript.sh "failed to run the mount command"
Вот часть содержимого временного файла:
LGT_TEMP_FILE = "$(mktemp --suffix .cmd)"
cat<<EOF>$LGT_TEMP_FILE
@echo off
set LGT_EXITCODE = "$LGT_ID"
exit /b %LGT_ID%
EOF
unix2dos "$LGT_TEMP_FILE"
Вот функция для создания событий в WEVL:
__create_event () {
local cmd = "eventcreate /ID $LGT_ID /L Application /SO $LGT_SOURCE /T $LGT_PRIORITY /D "
if [[ "$1" == *';'* ]]; then
local IFS=';'
for i in "$1"; do
$cmd "$i" &>/dev/null
done
else
$cmd "$LGT_DESC" &>/dev/null
fi
}
Выполнение пакетного сценария и вызов __create_event:
cmd /c "$(cygpath -wa "$LGT_TEMP_FILE")"
__create_event
Стоит отметить, что файлы .BAT и .CMD работают по-разному.
Читая https://ss64.com/nt/errorlevel.html, он отмечает следующее:
There is a key difference between the way .CMD and .BAT batch files set errorlevels:
An old .BAT batch script running the 'new' internal commands: APPEND, ASSOC, PATH, PROMPT, FTYPE and SET will only set ERRORLEVEL if an error occurs. So if you have two commands in the batch script and the first fails, the ERRORLEVEL will remain set even after the second command succeeds.
This can make debugging a problem BAT script more difficult, a CMD batch script is more consistent and will set ERRORLEVEL after every command that you run [source].
Это доставляло мне нескончаемые страдания, поскольку я выполнял последовательные команды, но УРОВЕНЬ ОШИБКИ останется неизменным даже в случае сбоя.
Также спрашивали у SuperUser: Как проверить код выхода последней команды в пакетном файле?