que - ¿Cómo obtengo el código de salida de la aplicación desde una línea de comando de Windows?
linea de comandos windows (7)
Estoy ejecutando un programa y quiero ver cuál es su código de retorno (ya que devuelve códigos diferentes en función de diferentes errores).
Sé que en Bash puedo hacer esto corriendo
echo $?
¿Qué hago cuando uso cmd.exe en Windows?
En un momento necesario, tuve que enviar con precisión los eventos de registro de Cygwin al 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 del 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í hay 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
}
Ejecutando el script por lotes y llamando a __create_event:
cmd /c "$(cygpath -wa "$LGT_TEMP_FILE")"
__create_event
Es posible que no funcione correctamente cuando se utiliza un programa que no está conectado a la consola, ya que la aplicación podría seguir funcionando mientras creas que tienes el código de salida. Una solución para hacerlo en C ++ se ve 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;
}
Las pruebas ErrorLevel
funcionan para las aplicaciones de consola , pero como indica dmihailescu , esto no funcionará si está intentando ejecutar una aplicación de ventana (por ejemplo, basada en Win32) desde un indicador de comandos. Una aplicación con ventanas se ejecutará en segundo plano, y el control volverá inmediatamente al símbolo del sistema (lo más probable es que con un ErrorLevel
de cero para indicar que el proceso se creó correctamente). Cuando una aplicación de ventana finalmente sale, su estado de salida se pierde.
Sin embargo, en lugar de usar el iniciador de C ++ basado en consola mencionado en otra parte, una alternativa más simple es iniciar una aplicación de ventana utilizando el comando START /WAIT
del símbolo del sistema. Esto iniciará la aplicación de ventana, esperará a que salga y, a continuación, devolverá el control al símbolo del sistema con el estado de salida del proceso establecido en ErrorLevel
.
start /wait something.exe
echo %errorlevel%
Si desea hacer coincidir exactamente el código de error (por ejemplo, es igual a 0), use esto:
@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
coincide con errorlevel
> = 0. ¿Ver if /?
.
Utilice la variable ERRORLEVEL incorporada:
echo %ERRORLEVEL%
¡Pero tenga cuidado si una aplicación ha definido una variable de entorno llamada ERRORLEVEL !
Vale la pena señalar que los archivos .BAT y .CMD funcionan de manera diferente.
Al leer https://ss64.com/nt/errorlevel.html se observa lo siguiente:
Hay una diferencia clave entre la forma en que los archivos de proceso por lotes .CMD y .BAT establecen los niveles de error:
Un antiguo script por lotes .BAT que ejecuta los ''nuevos'' comandos internos: APPEND, ASSOC, PATH, PROMPT, FTYPE y SET solo establecerá ERRORLEVEL si se produce un error. Por lo tanto, si tiene dos comandos en el script por lotes y el primero falla, ERRORLEVEL permanecerá configurado incluso después de que el segundo comando tenga éxito.
Esto puede hacer que la depuración de un script BAT problemático sea más difícil, un script por lotes de CMD es más consistente y establecerá ERRORLEVEL después de cada comando que ejecute [source].
Esto me estaba causando un sinfín de dolores, ya que estaba ejecutando comandos sucesivos, pero ERRORLEVEL permanecería sin cambios incluso en el caso de una falla.
Una variable de pseudo entorno llamada 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 detalles.
Ejemplo
@echo off
my_nify_exe.exe
if errorlevel 1 (
echo Failure Reason Given is %errorlevel%
exit /b %errorlevel%
)
Advertencia: si establece un nombre de variable de entorno errorlevel
, %errorlevel%
devolverá ese valor y no el código de salida. Utilice (set errorlevel=
) para borrar la variable de entorno, permitiendo el acceso al valor verdadero de errorlevel
través de la variable de entorno %errorlevel%
.