Come posso ottenere il codice di uscita dell'applicazione da una riga di comando di Windows?


797

Sto eseguendo un programma e voglio vedere qual è il suo codice di ritorno (poiché restituisce codici diversi in base a diversi errori).

So che in Bash posso farlo correndo

echo $?

Cosa devo fare quando utilizzo cmd.exe su Windows?



1
Googled per "Win8 Come ottenere il prompt CMD per mostrare lo stato di uscita" come possiamo fare in Linux. Questa era la migliore selezione ed è accurata.
SDsolar,

1
Puoi vedere rapidamente quale app restituisce:app.exe & echo %errorlevel%
marbel82

Risposte:


976

Una variabile di ambiente pseudo denominata errorlevelmemorizza il codice di uscita:

echo Exit Code is %errorlevel%

Inoltre, il ifcomando ha una sintassi speciale:

if errorlevel

Vedi if /?per i dettagli.

Esempio

@echo off
my_nify_exe.exe
if errorlevel 1 (
   echo Failure Reason Given is %errorlevel%
   exit /b %errorlevel%
)

Avviso: se si imposta un nome di variabile di ambiente errorlevel, %errorlevel%verrà restituito quel valore e non il codice di uscita. Utilizzare ( set errorlevel=) per cancellare la variabile di ambiente, consentendo l'accesso al valore reale errorleveltramite la %errorlevel%variabile di ambiente.


38
Se stai eseguendo direttamente da una riga di comando di Windows e vedi sempre 0 restituito, vedi la risposta di Gary: stackoverflow.com/a/11476681/31629
Ken

9
Anche se sei in PowerShell puoi usareecho Exit Code is $LastExitCode
Brandon Pugh il

11
Nota: "errorlevel 1" è vero se errorlevel> = 1. Quindi "errorlevel 0" corrisponderà a tutto. Vedi se /?". Invece, puoi usare "if% ERRORLEVEL% EQU 0 (..)".
Curtis Yallop,

1
Trovati casi in cui %ERRORLEVEL%è 0 anche se si è verificato un errore. È successo durante il check %ERRORLEVEL%in di un file cmd. Provare start /waitnon ha funzionato. L'unica cosa che ha funzionato èif errorlevel 1 (...)
AlikElzin-Kilaka,

1
Consiglio amichevole:% ErrorLevel% è una variabile shell, non una variabile d'ambiente, e restituisce anche una stringnon an int, il che significa che non è possibile utilizzare EQ/ NEQefficacemente.
kayleeFrye_onDeck

277

Il test ErrorLevelfunziona per le applicazioni console , ma come suggerito da dmihailescu , questo non funzionerà se si sta tentando di eseguire un'applicazione con finestra (ad esempio basata su Win32) da un prompt dei comandi. Un'applicazione con finestra verrà eseguita in background e il controllo tornerà immediatamente al prompt dei comandi (molto probabilmente con uno ErrorLevelzero per indicare che il processo è stato creato correttamente). Quando alla fine esce un'applicazione con finestre, il suo stato di uscita viene perso.

Invece di utilizzare il launcher C ++ basato su console menzionato altrove, tuttavia, un'alternativa più semplice è avviare un'applicazione con finestre usando il comando del prompt dei START /WAITcomandi. Ciò avvierà l'applicazione con finestre, attenderà la sua uscita, quindi restituirà il controllo al prompt dei comandi con lo stato di uscita del processo impostato ErrorLevel.

start /wait something.exe
echo %errorlevel%

20
Grazie mille per l'idea "START / wait". Ha funzionato per me :)
Timotei,

3
bella presa. Non sapevo di quel comando. L'ho appena visto funzionare per> start / wait notepad.exe
dmihailescu il

1
Un altro motivo per cui potrebbe non funzionare (sempre zero) è quando si trova all'interno di un ifo for. Prendi !errorlevel!invece in considerazione l'uso , come descritto in questa risposta .
Roman Starkov


23

Se si desidera abbinare esattamente il codice di errore (ad es. Uguale a 0), utilizzare questo:

@echo off
my_nify_exe.exe
if %ERRORLEVEL% EQU 0 (
   echo Success
) else (
   echo Failure Reason Given is %errorlevel%
   exit /b %errorlevel%
)

if errorlevel 0partite errorlevel> = 0. Vedi if /?.


Fa distinzione tra maiuscole e minuscole?
Nishant,

1
No. var, comandi (incluso "if") e "equ" funzionano indipendentemente dal caso.
Curtis Yallop,

14

Potrebbe non funzionare correttamente quando si utilizza un programma non collegato alla console, poiché tale app potrebbe essere ancora in esecuzione mentre si ritiene di avere il codice di uscita. Una soluzione per farlo in C ++ è la seguente:

#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;
}

In alcune configurazioni è necessario aggiungere #include <atlstr.h> in modo che il tipo CString venga ricongiunto.
Jake OPJ,

8

Vale la pena notare che i file .BAT e .CMD funzionano in modo diverso.

Leggendo https://ss64.com/nt/errorlevel.html si nota quanto segue:

Esiste una differenza fondamentale tra il modo in cui i file batch .CMD e .BAT impostano i livelli di errore:

Un vecchio script batch .BAT che esegue i "nuovi" comandi interni: APPEND, ASSOC, PATH, PROMPT, FTYPE e SET imposterà ERRORLEVEL solo se si verifica un errore. Quindi se hai due comandi nello script batch e il primo fallisce, ERRORLEVEL rimarrà impostato anche dopo che il secondo comando avrà esito positivo.

Ciò può rendere più difficile il debug di uno script BAT problematico, uno script batch CMD è più coerente e imposterà ERRORLEVEL dopo ogni comando che si esegue [sorgente].

Ciò non causava fine al dolore mentre eseguivo i comandi successivi, ma ERRORLEVEL sarebbe rimasto invariato anche in caso di guasto.


0

A un certo punto avevo bisogno di inviare con precisione gli eventi del registro da Cygwin al registro degli eventi di Windows. Volevo che i messaggi in WEVL fossero personalizzati, con il codice di uscita, i dettagli, le priorità, i messaggi, ecc. Corretti. Quindi ho creato un piccolo script Bash per occuparmene. Eccolo su GitHub, logit.sh .

Alcuni estratti:

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"

Ecco la parte del contenuto del file temporaneo:

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"

Ecco una funzione per creare eventi in 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
}

Esecuzione dello script batch e chiamata su __create_event:

cmd /c "$(cygpath -wa "$LGT_TEMP_FILE")"
__create_event
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.