Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows command interpreter: how to obtain exit code of first piped command

In the example provided below, I execute nmake and then redirect STDOUT/STDERR to tee, which then sends it to the screen, and also to a log file. The problem is that I'm trying to capture the exit code for nmake and not tee. What I need is the exit code from nmake, and not tee.

nmake | tee output.txt
like image 516
doberkofler Avatar asked Jun 23 '12 15:06

doberkofler


People also ask

How do I get an exit code?

To check the exit code we can simply print the $? special variable in bash. This variable will print the exit code of the last run command.

How do I find my return code using cmd?

To display the exit code for the last command you ran on the command line, use the following command: $ echo $?

How do you exit something in cmd?

At the command prompt, type exit. Depending on the device configuration, you may be presented with another menu, for example: Access selection menu: a: Admin CLI s: Shell q: Quit Select access or quit [admin] : Type q or quit to exit.

How do I go back one step in cmd?

Type cd \ into the prompt to go back to the directory. If you need to navigate from a location back to the main command prompt, this command takes you back immediately.


2 Answers

You might think you could do something like the following, but it won't work.

(nmake & call set myError=%%errorlevel%%) | tee output.txt

The problem lies in the mechanism by which Windows pipes work. Each side of the pipe is executed in it's own CMD shell. So any environment variable you set there will disappear once the command has finished. Also the delayed expansion of %errorlevel% is more complicated because of the extra level of parsing, and because the CMD shell has a command line context instead of a batch context.

You could do something like this:

(nmake & call echo %%^^errorlevel%% ^>myError.txt) | tee output.txt
for /f %%A in (myError.txt) do echo nmake returned %%A
del myError.txt

Or you could embed the errorlevel in your output.txt:

(nmake & call echo nmakeReturnCode: %%^^errorlevel%%) | tee output.txt
for /f "tokens=2" %%A in ('findstr /b "nmakeReturnCode:" output.txt') do echo nmake returned %%A

Both solutions above assume you are running the commands in a batch script. If you are executing the commands from the command line instead, then both solutions above need
%^^errorlevel% instead of %%^^errorlevel%%.

But given that nmake does not require user input, and it is usually fast so real time monitoring is probably not an issue, then the simplest solution seems to be

nmake >output.txt
set myError=%errorlevel%
type output.txt
echo nmake returned %myError%


Note - there are many subtle complications when working with Windows pipes. A good reference is Why does delayed expansion fail when inside a piped block of code?. I recommend reading the question and all the answers. The selected answer has the best info, but the other answers help provide context.

EDIT 2015-06-02

I've recently discovered you can use DOSKEY macros to cleanly store and retrieve the ERRORLEVEL from either (or both) sides of a pipe, without resorting to a temporary file. I got the idea from DosTips user Ed Dyreen at http://www.dostips.com/forum/viewtopic.php?p=41409#p41409. DOSKEY macros cannot be executed via batch, but the definitions persist after ENDLOCAL and CMD /C exit!

Here is how you would use it in your situation:

(nmake & call doskey /exename=err err=%%^^errorlevel%%) | tee output.txt
for /f "tokens=2 delims==" %%A in ('doskey /m:err') do echo nmake returned %%A

If you want, you can add one more command at the end to clear the definition of the err "macro" after you have retrieved the value.

doskey /exename=err err=
like image 108
dbenham Avatar answered Sep 25 '22 17:09

dbenham


There is a version of "tee" (called mtee => https://ritchielawrence.github.io/mtee/) that optionally adopts the exit code of the piped process. With that you could write

nmake | mtee /E output.txt
like image 27
Hardy Avatar answered Sep 24 '22 17:09

Hardy