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

前端 未结 6 938
天涯浪人
天涯浪人 2021-01-03 18:22

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

相关标签:
6条回答
  • 2021-01-03 18:43

    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.

    0 讨论(0)
  • 2021-01-03 18:44

    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.

    0 讨论(0)
  • 2021-01-03 18:58

    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
    )
    
    0 讨论(0)
  • 2021-01-03 19:01

    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.

    0 讨论(0)
  • 2021-01-03 19:03

    One workaround is to make an indirection through a file.

    Like this

    foo.exe > tmp.txt
    set FOOERR=%ERRORLEVEL%
    cat tmp.txt
    exit %FOOERR%
    
    0 讨论(0)
  • 2021-01-03 19:03

    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.

    0 讨论(0)
提交回复
热议问题