How do I get the error level of commands in a pipe in Windows batch programming?

社会主义新天地 提交于 2019-11-30 00:11:24

问题


Batch files return the error code of the last command by default.

Is it somehow possible to return the error code of a former command. Most notably, is it possible to return the error code of a command in a pipe?

For example, this one-line batch script

foo.exe

returns the error code of foo. But this one:

foo.exe | tee output.txt

always returns the exit code of tee, which is zero.


回答1:


I had a similar problem and settled on the following solution as I did not need to detect the exact error code just success or failure.

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
)



回答2:


One workaround is to make an indirection through a file.

Like this

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



回答3:


The %ERRORLEVEL% variable doesn't get updated before the piped command is run; you have to use a wrapper as advised in the other answers.

However, you can use "IF ERRORLEVEL #". For example:

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

The ECHO will only run if an error was returned; however %ERRORLEVEL% seems inconsistent.

Edit: Changed example to be runnable as-is.




回答4:


The script

foo.exe && set dummy= | tee output.txt

will return the error code of foo.exe. Adding some dummy command behind && preserves the exit code of the command before the &&. The exit code of the dummy command is irrelevant. The dummy command should not output anything, and preferably have no effect at all. Setting an environment variable as dummy command has no effect, because piped commands are executed in an own cmd shell.

If the command is part of a longer script, then the following line is useful, because it stops the execution of the script and returns the right exit code:

foo.exe && set dummy= | tee output.txt || exit /b !errorlevel! 

I tested this with Windows 7 and with Windows 10. However, I did not find any documentation that explains the behavior of the combination of && and |. Can anyone explain or refer to such documentation?




回答5:


After about one day of digging, I found a way to do that:

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_%

In the example above "%homeDir%%1" is being executed and its output is piped to "%homeDir%mtee". This line detects failures (I'd suggest you to draw a diagram of batch contexts and their stdin/stdout/stderr assignments in order to understand what it does :-) ). I did not find a good way to extract the actual errorlevel. The best thing I got was to replace the 'echo' command with some batch script call 'call rc.bat' which look like:

@echo %errorlevel%

and then replace 'set error_=1' with 'set error_=%%i'.

But the problem is that this call may fail too, and it is not easy to detect that. Still, it is much better than nothing -- I did not find any solution for that on the Internet.




回答6:


To call tee for entry bat-file, not for single command, and use errorlevel freely, I use trick like this:

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

it separates using tee from calling any commands inside batch.




回答7:


You can solve the problem by creating a wrapper around your command file:

rem wrapper for command file, wrapper.cmd

call foo.exe

echo %errorlevel%

if errorlevel 1 goto...

Then append tee to the wrapper:

wrapper.cmd | tee result.log

Of course this does not exactly the same, e.g. if you want to log in several files in the wrapped file, it is not possible, but in my case it solved the problem.



来源:https://stackoverflow.com/questions/877639/how-do-i-get-the-error-level-of-commands-in-a-pipe-in-windows-batch-programming

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!