utiles programacion programa por para lotes lenguaje ejemplos ejecutar crear comandos batch bat avanzados avanzada archivos archivo windows batch-file batch-processing

programacion - ¿Cómo obtengo el nivel de error de los comandos en un canal en la programación por lotes de Windows?



lenguaje batch (6)

Los archivos por lotes devuelven el código de error del último comando de forma predeterminada.

¿Es de alguna manera posible devolver el código de error de un comando anterior? En particular, ¿es posible devolver el código de error de un comando en una tubería?

Por ejemplo, este script por lotes de una sola línea

foo.exe

devuelve el código de error de foo . Pero este:

foo.exe | tee output.txt

siempre devuelve el código de salida de tee , que es cero.


Después de aproximadamente un día de excavar, encontré una forma de hacerlo:

set error_=0 9>&1 1>&2 2>&9 (for /f "delims=" %%i in (''9^>^&1 1^>^&2 2^>^&9 ^(^(^(2^>^&1 call "%homeDir%%1"^) ^|^| ^(1^>^&2 2^>nul echo FAILED^)^) ^| 2^>nul "%homeDir%mtee" /T /+ "%homeDir%logs/%date_%_%1.log"^)'') do (set error_=1)) exit /b %error_%

En el ejemplo anterior, "% homeDir %% 1" se está ejecutando y su salida se canaliza a "% homeDir% mtee". Esta línea detecta fallas (le sugiero que dibuje un diagrama de contextos por lotes y sus asignaciones stdin / stdout / stderr para comprender lo que hace :-)). No encontré una buena manera de extraer el nivel de error real. Lo mejor que obtuve fue reemplazar el comando ''echo'' con una llamada de script por lotes ''call rc.bat'' que se ve así:

@echo %errorlevel%

y luego reemplace ''set error_ = 1'' con ''set error _ = %% i''.

Pero el problema es que esta llamada también puede fallar, y no es fácil detectar eso. Aún así, es mucho mejor que nada, no encontré ninguna solución para eso en Internet.


La variable% ERRORLEVEL% no se actualiza antes de que se ejecute el comando canalizado; tienes que usar un contenedor como se aconseja en las otras respuestas.

Sin embargo, puede usar "IF ERRORLEVEL #". Por ejemplo:

( type filename @REM Use an existing (or not) filename to test each branch IF ERRORLEVEL 1 (echo ERROR) ELSE (echo OKAY) ) > logfile.txt

ECHO solo se ejecutará si se devuelve un error; sin embargo,% ERRORLEVEL% parece inconsistente.

Editar: Ejemplo modificado para ser ejecutable tal como está.


Para llamar al tee para la entrada bat-file, no para un solo comando, y usar errorlevel libremente, utilizo el truco de esta manera:

if "%1" == "body" goto :body call %0 body | tee log.txt goto :eof :body set nls_lang=american_america set HomePath=%~dp0 sqlplus "usr/pwd@tnsname" "@%HomePath%script.sql" if errorlevel 1 goto dberror rem Here I can do something which is dependent on correct finish of script.sql :dberror echo script.sqlerror failed

se separa al usar tee para llamar a cualquier comando dentro del lote.


Puede resolver el problema creando un contenedor alrededor de su archivo de comando:

rem wrapper for command file, wrapper.cmd call foo.exe echo %errorlevel% if errorlevel 1 goto...

A continuación, agregue tee a la envoltura:

wrapper.cmd | tee result.log

Por supuesto, esto no es exactamente lo mismo, por ejemplo, si desea iniciar sesión en varios archivos en el archivo envuelto, no es posible, pero en mi caso solucionó el problema.


Tuve un problema similar y resolví la siguiente solución, ya que no tuve que detectar el código de error exacto, solo éxito o error.

echo > .failed.tmp ( foo.exe && del .failed.tmp ) | tee foo.log if exist .failed.tmp ( del .failed.tmp exit /b 1 ) else ( exit /b 0 )


Una solución es hacer una indirección a través de un archivo.

Me gusta esto

foo.exe > tmp.txt set FOOERR=%ERRORLEVEL% cat tmp.txt exit %FOOERR%