2008-12-02 17 views
605

Estoy ejecutando un programa y quiero ver cuál es su código de retorno (ya que devuelve códigos diferentes basados ​​en diferentes errores).¿Cómo obtengo el código de salida de la aplicación desde una línea de comando de Windows?

Sé que en Bash puedo hacer esto ejecutando

echo $?

¿Qué hago cuando uso cmd.exe en Windows?

+6

También se preguntó en SuperUser: [¿Cómo comprobar el código de salida del último comando en el archivo por lotes?] (Http://superuser.com/q/194662/126252) – Deanna

Respuesta

734

Una variable de entorno llamada seudo errorlevel almacena el código de salida:

echo Exit Code is %errorlevel% 

Además, el comando if tiene una sintaxis especial:

if errorlevel 

Ver if /? para más detalles.

Ejemplo

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

Advertencia: Si se establece un entorno nombre de la variable errorlevel, %errorlevel% devolverá ese valor y no el código de salida. Use (establezca errorlevel=) para borrar la variable de entorno, lo que permite el acceso al verdadero valor de errorlevel a través de la variable de entorno %errorlevel%.

+24

Si está ejecutando directamente desde un Windows línea de comando y siempre viendo 0 devuelto, vea la respuesta de Gary: http://stackoverflow.com/a/11476681/31629 – Ken

+6

También si está en powershell puede usar 'echo Código de salida es $ LastExitCode' –

+9

Nota:" errorlevel 1 "es verdadero si errorlevel> = 1. Entonces" errorlevel 0 "coincidirá con todo. Ve si /?". En cambio, puede usar "if% ERRORLEVEL% EQU 0 (..)". –

82

Utilice el built-in ERRORLEVEL variable:

echo %ERRORLEVEL% 

Pero beware if an application has defined an environment variable named ERRORLEVEL!

+6

No es una variable de entorno real (que es, obviamente, por qué deja de funcionar si there * es * una variable nombrada de esa manera). – Joey

+1

tenga en cuenta que no funciona en powershell –

+11

@SteelBrain: Se llama '$ LastExitCode' en PowerShell. –

11

Es posible que no funcione correctamente cuando se utiliza un programa que no está conectado a la consola, porque esa aplicación aún podría estar ejecutándose mientras crees que tienes el código de salida. Una solución de hacerlo en C++ se parece a continuación:

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

Prueba ErrorLevel trabaja para consola aplicaciones, sino como insinuado por dmihailescu, esto no funcionará si usted está tratando de ejecutar una ventana aplicación (por ejemplo, basada en Win32) desde un símbolo del sistema. Se ejecutará una aplicación de ventana en segundo plano, y el control volverá inmediatamente al símbolo del sistema (muy probablemente con ErrorLevel de cero para indicar que el proceso fue creado con éxito). Cuando finalmente sale una aplicación con ventana, se pierde su estado de salida.

En lugar de utilizar el iniciador de C++ basado en consola mencionado en otra parte, una alternativa más simple es iniciar una aplicación con ventana utilizando el comando START /WAIT del símbolo del sistema. Esto iniciará la aplicación con ventana, esperará a que salga y luego devolverá el control al símbolo del sistema con el estado de salida del proceso establecido en ErrorLevel.

start /wait something.exe 
echo %errorlevel% 
+18

Muchas gracias por la idea de "INICIAR/esperar". Eso funcionó para mí :) – Timotei

+2

nice catch. No sabía sobre ese comando. Acabo de ver que funciona para> start/wait notepad.exe – dmihailescu

+1

¡Excelente respuesta! ¡Muchas gracias! –

9

Si desea hacer coincidir exactamente el código de error (por ejemplo, igual a 0), utilice la siguiente:

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

"si errorlevel 0" coincide con nivel de error> = 0. Ver "si /?".

0

Hubo un momento en el que tuve que presionar con precisión los eventos de registro de Cygwin en el registro de eventos de Windows. Quería que los mensajes en WEVL fueran personalizados, que tuvieran el código de salida correcto, los detalles, las prioridades, el mensaje, etc. Así que creé un pequeño script de Bash para encargarme de esto. Aquí está en GitHub, logit.sh.

Algunos extractos:

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" 

Aquí está la parte contenido del archivo temporal:

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" 

Aquí es una función para crear eventos en 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 
} 

Ejecución del lote script y llamada en __create_event:

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