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%