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 t
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.
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.
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
)
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.
One workaround is to make an indirection through a file.
Like this
foo.exe > tmp.txt
set FOOERR=%ERRORLEVEL%
cat tmp.txt
exit %FOOERR%
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.