Як отримати код виходу програми з командного рядка Windows?


797

Я запускаю програму і хочу побачити, який її код повернення (оскільки він повертає різні коди на основі різних помилок).

Я знаю, що в Bash я можу це зробити, бігаючи

ехо $?

Що робити під час використання cmd.exe для Windows?



1
Google для "Win8 Як отримати підказку CMD, щоб показати статус виходу", як ми можемо зробити в Linux. Це був найкращий вибір, і це точно.
— SDsolar

1
Ви можете швидко побачити, що додаток повертається:app.exe & echo %errorlevel%
— marbel82

Відповіді:


976

Змінна псевдосередовища з назвою 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%змінну оточення.


38
Якщо ви працюєте безпосередньо з командного рядка Windows і завжди бачите 0 повернених, дивіться відповідь Гері: stackoverflow.com/a/11476681/31629
— Кен

9
Також якщо ви перебуваєте в повному складі, то можете скористатисяecho Exit Code is $LastExitCode
— Брендон П'ю

11
Примітка: "errorlevel 1" вірно, якщо errorlevel> = 1. Отже, "errorlevel 0" відповідатиме всім. Дивіться "якщо /?". Натомість ви можете використовувати "if% ERRORLEVEL% EQU 0 (..)".
— Кертіс Яллоп

1
Знайдено випадки, коли %ERRORLEVEL%0, навіть якщо сталася помилка. Сталося під час перевірки %ERRORLEVEL%у cmd-файлі. Спроба start /waitне спрацювала. Єдине, що працювалоif errorlevel 1 (...)
— АлікЕльзін-кілака

1
Дружні поради:% ErrorLevel% - це змінна оболонка, а не змінна середовище; вона також повертає значення " stringне" int, тобто ви не можете використовувати EQ/ NEQефективно.
— kayleeFrye_onDeck

277

Тестування ErrorLevelпрацює для консольних програм, але, як натякнув dmihailescu , це не спрацює, якщо ви намагаєтеся запустити віконний додаток (наприклад, на основі Win32) з командного рядка. Віконна програма буде працювати у фоновому режимі, а керування негайно повернеться до командного рядка (швидше за все, з ErrorLevelнулем, щоб вказати, що процес створений успішно). Коли врезультатно закрита програма закривається, її статус виходу втрачається.

Замість використання консольного C ++-пускового пристрою, згаданого в іншому місці, однак, більш простою альтернативою є запуск віконної програми за допомогою команди командного рядка START /WAIT. Це запустить віконну програму, зачекає її виходу, а потім поверне управління до командного рядка зі статусом виходу процесу, встановленого в ErrorLevel.

start /wait something.exe
echo %errorlevel%

20
Велике спасибі за ідею "СТАРТ / чекай". Це працювало для мене :)
— Тимотей

3
приємний улов. Я не знав про цю команду. Я щойно бачив, як це працює для> start / wait notepad.exe
— dmihailescu

1
Ще одна причина, чому вона може не працювати (завжди дорівнює нулю), - це коли вона знаходиться всередині ifабо for. Розглянемо !errorlevel!натомість використання , як описано у цій відповіді .
— Роман Старков

100

Використовуйте вбудовану змінну ERRORLEVEL:

echo %ERRORLEVEL%

Але будьте обережні, якщо програма визначила змінну середовища з назвою ERRORLEVEL !


6
Це не фактична змінна оточення (що, очевидно, чому вона перестає працювати , якщо є змінна з ім'ям , що шлях).
— Joey

17
@SteelBrain: Це називається $LastExitCodeв PowerShell.
— Олексій А.

23

Якщо ви хочете точно відповідати коду помилки (наприклад, дорівнює 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 /?.


Це залежно від регістру?
— Нішант

1
Ні. Vars, команди (включаючи "if") та "equ" працюють, незалежно від випадку.
— Кертіс Яллоп

14

Можливо, він не працює належним чином при використанні програми, не прикріпленої до консолі, тому що ця програма все ще може працювати, поки ви думаєте, що у вас є вихідний код. Рішення зробити це на 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 був повторно розпізнаний.
— Джейк OPJ

8

Варто зазначити, що файли .BAT і .CMD працюють по-різному.

Читаючи https://ss64.com/nt/errorlevel.html, вона зазначає наступне:

Існує ключова різниця між способом .CMD і .BAT-пакетних файлів, що встановлюють рівні помилок:

Старий пакетний скрипт .BAT, який виконує внутрішні команди 'new': APPEND, ASSOC, PATH, PROMPT, FTYPE і SET, встановить ERRORLEVEL лише у випадку помилки. Отже, якщо у пакетного скрипту у вас є дві команди, і перша не вдалася, ERRORLEVEL залишиться встановленою навіть після успіху другої команди.

Це може ускладнити налагодження проблемного BAT-скрипту, пакетний сценарій CMD є більш послідовним і встановить ERRORLEVEL після кожної команди, яку ви запускаєте [source].

Це не викликало у мене скорботи, коли я виконував послідовні команди, але ERRORLEVEL залишився незмінним навіть у разі відмови.


0

Якось мені потрібно було точно пересувати події журналу з 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.