批处理文件默认返回最后一条命令的错误码。
是否有可能返回前一个命令的错误代码。最值得注意的是,是否可以在管道中返回命令的错误代码?
例如,这个单行批处理脚本
foo.exe
返回foo的错误代码。但是这个:
foo.exe | tee output.txt
总是返回tee的退出代码,该代码为零。
批处理文件默认返回最后一条命令的错误码。
是否有可能返回前一个命令的错误代码。最值得注意的是,是否可以在管道中返回命令的错误代码?
例如,这个单行批处理脚本
foo.exe
返回foo的错误代码。但是这个:
foo.exe | tee output.txt
总是返回tee的退出代码,该代码为零。
我遇到了类似的问题并选择了以下解决方案,因为我不需要检测确切的错误代码只是成功或失败。
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
)
%ERRORLEVEL% 变量在管道命令运行之前不会更新;您必须按照其他答案中的建议使用包装器。
但是,您可以使用“IF ERRORLEVEL #”。例如:
(
type filename
@REM Use an existing (or not) filename to test each branch
IF ERRORLEVEL 1 (echo ERROR) ELSE (echo OKAY)
) > logfile.txt
ECHO 只有在返回错误时才会运行;但是 %ERRORLEVEL% 似乎不一致。
编辑:将示例更改为可按原样运行。
一种解决方法是通过文件进行间接寻址。
像这样
foo.exe > tmp.txt
set FOOERR=%ERRORLEVEL%
cat tmp.txt
exit %FOOERR%
经过大约一天的挖掘,我找到了一种方法:
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_%
在上面的示例中,“%homeDir%%1”正在执行,其输出通过管道传输到“%homeDir%mtee”。此行检测失败(我建议您绘制批处理上下文及其 stdin/stdout/stderr 分配的图表,以了解它的作用:-))。我没有找到提取实际错误级别的好方法。我得到的最好的事情是用一些批处理脚本调用'call rc.bat'替换'echo'命令,它看起来像:
@echo %errorlevel%
然后将 'set error_=1' 替换为 'set error_=%%i'。
但问题是这个调用也可能失败,而且不容易检测到。尽管如此,它总比没有好 - 我在互联网上没有找到任何解决方案。
要为入口 bat 文件调用 tee,而不是为单个命令调用,并自由使用 errorlevel,我使用这样的技巧:
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
它将使用 tee 与调用批处理中的任何命令分开。
您可以通过在命令文件周围创建包装器来解决此问题:
rem wrapper for command file, wrapper.cmd
call foo.exe
echo %errorlevel%
if errorlevel 1 goto...
然后将 tee 附加到包装器:
wrapper.cmd | tee result.log
当然,这并不完全相同,例如,如果您想在打包文件中登录多个文件,这是不可能的,但在我的情况下它解决了问题。