Come ottengo il codice di uscita dell’applicazione da una riga di comando di Windows?

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 faccio quando utilizzo cmd.exe su Windows?

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

 echo Exit Code is %errorlevel% 

Inoltre, il comando if ha una syntax speciale:

 if errorlevel 

Vedi if /? per dettagli.

Esempio

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

Attenzione: se imposti un nome errorlevel variabile di ambiente, %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% .

Test ErrorLevel funziona per le applicazioni della console , ma come suggerito da dmihailescu , questo non funzionerà se si sta tentando di eseguire un’applicazione con windows (ad esempio Win32) da un prompt dei comandi. Un’applicazione con windows verrà eseguita in background e il controllo tornerà immediatamente al prompt dei comandi (molto probabilmente con un ErrorLevel di zero per indicare che il processo è stato creato correttamente). Alla fine, quando un’applicazione a windows viene chiusa, lo stato di uscita viene perso.

Invece di usare il launcher C ++ basato su console menzionato altrove, però, un’alternativa più semplice è avviare un’applicazione windowed usando il comando START /WAIT del prompt dei comandi. Ciò avvierà l’applicazione a windows, attenderà che esca e quindi restituirà il controllo al prompt dei comandi con lo stato di uscita del processo impostato in ErrorLevel .

 start /wait something.exe echo %errorlevel% 

Usa la variabile ERRORLEVEL integrata:

 echo %ERRORLEVEL% 

Ma attenzione se un’applicazione ha definito una variabile d’ambiente chiamata ERRORLEVEL !

Potrebbe non funzionare correttamente quando si utilizza un programma che non è collegato alla console, poiché l’app potrebbe essere ancora in esecuzione mentre si pensa 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; } 

Se vuoi far corrispondere esattamente il codice di errore (eg uguale a 0), usa 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 0 corrisponde a errorlevel > = 0. Vedi if /? .

A un certo punto avevo bisogno di spingere con precisione gli eventi del registro da Cygwin al registro eventi di Windows. Volevo che i messaggi in WEVL fossero personalizzati, che avessero il codice di uscita corretto, i dettagli, le priorità, il messaggio, ecc. Così ho creato un piccolo script di Bash per occuparmi di questo. Eccolo su GitHub, logit.sh .

Alcuni estratti:

 usage: logit.sh [-h] [-p] [-i=n] [-s]  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<$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 richiamo su __create_event:

 cmd /c "$(cygpath -wa "$LGT_TEMP_FILE")" __create_event