Domanda

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

So che in Bash posso farlo eseguendo

  

echo $?

Cosa devo fare quando utilizzo cmd.exe su Windows?

È stato utile?

Soluzione

Una variabile di ambiente pseudo denominata errorlevel memorizza il codice di uscita:

echo Exit Code is %errorlevel%

Inoltre, il comando if 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% restituirà quel valore e non il codice di uscita. Utilizzare ( set errorlevel = ) per cancellare la variabile di ambiente, consentendo l'accesso al valore reale di errorlevel tramite la variabile di ambiente % errorlevel% .

Altri suggerimenti

Test ErrorLevel funziona per le applicazioni console , ma come suggerito da di dmihailescu , questo non funzionerà se stai tentando di eseguire un'applicazione con finestre (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 un ErrorLevel pari a zero 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 START / WAIT del prompt dei comandi. 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 in ErrorLevel .

start /wait something.exe
echo %errorlevel%

Utilizza la variabile ERRORLEVEL integrata:

echo %ERRORLEVEL%

Ma attenzione se un'applicazione ha definito una variabile di ambiente denominata ERRORLEVEL !

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%
)

se errorlevel 0 corrisponde a errorlevel > = 0. Vedi if /? .

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 disporre del codice di uscita. Una soluzione per farlo in C ++ è simile al 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;
}

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

Leggendo https://ss64.com/nt/errorlevel.html rileva 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 [source].

Questo non mi causava fine al dolore mentre stavo eseguendo comandi successivi, ma ERRORLEVEL sarebbe rimasto invariato anche in caso di guasto.

Ad 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top