I'm trying to figure out if it's possible to get the ERRORLEVEL
value from the first item in a pipe sequence.
For example, a batch file containing
the following:
@echo off
dir c:\ /badarg | more
echo ERRORLEVEL %ERRORLEVEL%
gives the output:
ERRORLEVEL 0
despite the fact that "/badarg" is an invalid flag to the dir
command.
I think this must be because later item(s) in the sequence
("more" in my contrived example) can reset ERRORLEVEL to 0.
I'm trying to do this in batch files on Win2k and
WinXP Pro machines. I'd appreciate any ideas anyone
cares to share.
Thanks,
Don
I take this an example and guess you know about the /P switch
of dir ;-)
There is AFAIK no solution to this. Dir and more run simulaneously,
more does return without an error, so errorlevel 0 is correct.
Combinations of redirection and conditional execution fail also in
this context.
@echo off
(dir c:\ /badarg ||goto :error )|more
echo we shouldn't reach here
goto :eof
:error
echo ERRORLEVEL %ERRORLEVEL%
while this works
@echo off
dir c:\ /badarg ||goto :error
echo we shouldn't reach here
goto :eof
:error
echo ERRORLEVEL %ERRORLEVEL%
To check if dir has an error condition you might redirect dir error
output to a file and check for it.
@echo off
del /q dir.err >NUL 2>&1
dir c:\ /badarg 2>dir.err |more
if exist dir.err echo there was a problem with dir c:\ /badarg
HTH
--
Gruesse Greetings Saludos Saluti Salutations
Matthias
---------+---------+---------+---------+---------+---------+---------+
> foxidrive wrote:
>> I'm not sur if this is helpful but this will only execute more on an
>> errorlevel of 0
>>
>> dir c:\ /badarg && more
>>
>> and this on errorlevel 1
>>
>> dir c:\ /badarg || more
>
> Hi foxidrive.
>
> Despite the similarity of the ||, condtinal execution doesn't include
> redirection. So it's running more without redir which means standard
> input is the keyboard then. You have to hit ctrl-c/-break or [F6]/
> ctrl-z + return to exit more.
>
> HTH
Thanks for pointing that out, Matthias. :)
> Hi all,
>
> I'm trying to figure out if it's possible to get the ERRORLEVEL
> value from the first item in a pipe sequence.
> For example, a batch file containing
> the following:
>
> @echo off
> dir c:\ /badarg | more
> echo ERRORLEVEL %ERRORLEVEL%
>
> gives the output:
> ERRORLEVEL 0
>
> despite the fact that "/badarg" is an invalid flag to the dir
> command.
I'm not sur if this is helpful but this will only execute more on an
Hi foxidrive.
Despite the similarity of the ||, condtinal execution doesn't include
redirection. So it's running more without redir which means standard
input is the keyboard then. You have to hit ctrl-c/-break or [F6]/
ctrl-z + return to exit more.
HTH
--
Sorry; it was an admittedly a poor example; I was trying to avoid
extraneous issues, but maybe it would be better to explain more
fully what I'm trying to do.
What I really have instead of the dir command is a batch file, and
instead of the more command, a Tee exectuable.
I started with just the batch file, which I'm invoking from C++
code. Currently, I've got the batch file checking ERRORLEVEL
after each step in the sequence of things that it does, and
doing an:
EXIT /B %ERRORLEVEL%
if ERRORLEVEL isn't zero.
(or EXIT /B 0 at the end to indicate successful completion of the
entire batch file).
I'm able within the C++ code to check the return status of
the batch file,
But now, I'm trying to add using the Tee executable to capture the
output of the batch file to a logfile - so my C++ code is trying
to invoke something like:
MyBatchFile.bat | Tee.exe -o MyLogFIle.txt
The Tee executable is returning 0 to indicate successful completion,
and apparently that's the return status that my C++ code always sees,
no matter what the batch file exited with.
I guess I could have the batch file create an output file with its
return code, and have the C++ code read that, but I was hoping to
keep it checking the return code if at all possible.
Maybe there's an alternate to using a pipe and the Tee utility?
I saw a discussion over on alt.msdos.batch about a console I/O
capture utility called TCAP, but it apparently doesn't work on Win2k
or WinXP (my target platforms).
Thank you for replying (you too, foxidrive!) and for your help,
Don
Looks like you should take your tee inside the batch ;-)
The advantage of true pipes is the simultaneously reaction, you know
the disadvantage now.
I suggest you hide the tee and error checks inside the batch.
MyBatchFile.bat -o MyLogFIle.txt
if the error condition occurs in the middle of a task with tee'd
output it may be possible to check before.
What is the scope of the batch?
I don't understand - I'd still have to pipe each command/executable
invocation in the batch file into Tee.exe. Won't that just
overwrite ERRORLEVEL with the return code of Tee at each step?
Sorry if I'm being dense...
Don
No way for me to look into that black box from here ;-)
If you feel the need to hide details try to describe less abstract
than the dir|more thing.
HTH
Ok, good suggestion; here's a small but concrete example.
Given this batch file MyBatchFile.bat:
@echo off
myConsoleApp1.exe -i input1.txt -o output1.txt
if ERRORLEVEL=1 EXIT /B %ERRORLEVEL%
myConsoleApp2.exe -i input2.txt -o output2.txt
if ERRORLEVEL=1 EXIT /B %ERRORLEVEL%
EXIT /B 0
I can invoke MyBatchFile.bat from my C++ code,
and after it completes, get the return value it
returned from within my C++ code.
I invoke the batch file using CreateProcess(), operating on
the command line
"cmd /C call MyBatchFile.bat",
and get the batch file's return status using
GetExitCodeProcess().
Now if I change the command line to
"cmd /C call MyBatchFile.bat | Tee.exe -o MyLogfile.txt",
the return status that I get within my C++ code using
GetExitCodeProcess() is the return code from Tee.exe,
as previously noted.
If I go back to the original invocation of my batch file, and
change the batch file to take Tee inside of it, producing this:
@echo off
myConsoleApp1.exe -i input1.txt -o output1.txt | Tee.exe -o
MyLogfile.txt
if ERRORLEVEL=1 EXIT /B %ERRORLEVEL%
myConsoleApp2.exe -i input2.txt -o output2.txt | Tee.exe -a -o
MyLogfile.txt
if ERRORLEVEL=1 EXIT /B %ERRORLEVEL%
EXIT /B 0
then the return codes from MyConsoleApp1 and MyConsoleApp2
are overwritten by Tee.exe's return code (0) - so my batch file always
exits with a return code of 0, and that's what my C++ code always sees.
Thank you for persevering with my rambling explanations,
and for your help.
Don
Do myConsoleApp1.exe and myConsoleApp2.exe use erroroutput which can
be redirected separately? If they do, this may work:
@echo off
del /q err >NUL 2>&1
myConsoleApp1.exe -i input1.txt -o output1.txt 2>err | Tee.exe -o MyLogfile.txt
if exist err EXIT /B 1
myConsoleApp2.exe -i input2.txt -o output2.txt 2>err | Tee.exe -a -o MyLogfile.txt
if exist err EXIT /B 1
EXIT /B 0
If they do not, you may filter MyLogfile.txt on any errormessages
and abort with an errorlevel if found.
But for now (after having a beer) I'm tired of shooting in the dark ;-)
Seems to me that it was pointed out in an earlier post that the "/B" option
may not work. Why not try this instead:
@echo off
del /q err >NUL 2>&1
myConsoleApp1.exe -i input1.txt -o output1.txt 2>err | Tee.exe -o
MyLogfile.txt
if exist err EXIT 1
myConsoleApp2.exe -i input2.txt -o output2.txt 2>err | Tee.exe -a -o
MyLogfile.txt
if exist err EXIT 1
EXIT
Note that, on its own, the EXIT command resets the errorlevel code to zero.
/Al
>Seems to me that it was pointed out in an earlier post that the "/B" option
>may not work. Why not try this instead:
>
> @echo off
> del /q err >NUL 2>&1
> myConsoleApp1.exe -i input1.txt -o output1.txt 2>err | Tee.exe -o
>MyLogfile.txt
> if exist err EXIT 1
> myConsoleApp2.exe -i input2.txt -o output2.txt 2>err | Tee.exe -a -o
>MyLogfile.txt
> if exist err EXIT 1
> EXIT
>
>Note that, on its own, the EXIT command resets the errorlevel code to zero.
>
>/Al
>
>
I think what you intend does not work as you intend:
W:\source ) if exist err echo exist
W:\source ) echo hello al 2>err | tee out
hello al
W:\source ) if exist err echo exist
exist
W:\source )
--
Walter Briscoe
Hello Walter,
this misses the point. Error output *may* be used by your
myConsoleApp1.exe and App2 - we don't know. Error output (when used)
can be redirected using its handle with the number 2, so 2>err
generates a file "err" without extension only if errors are reported.
If any error messages are in standard output you will have to filter
the logfile for these messages with find or findstr to detect them
and eventually discard the log.
I suggest you read the chapters on piping/redirection in the
windows w2k/xp help file
HTH
On Mon, 31 Jan 2005, Matthias Tacke wrote:
> this misses the point. Error output *may* be used by your
> myConsoleApp1.exe and App2 - we don't know. Error output (when used)
> can be redirected using its handle with the number 2, so 2>err
> generates a file "err" without extension only if errors are reported.
Are 100% sure it *generates* file only if errors are reported?
I did small test in w2k cmd:
=== screen capture ======
C:\>dir test 2> test2
Volume in drive C is PAREXEL
Volume Serial Number is 202C-C56F
Directory of C:\
31-01-2005 12:17 0 test
1 File(s) 0 bytes
0 Dir(s) 25,673,706,496 bytes free
C:\>dir test*
Volume in drive C is PAREXEL
Volume Serial Number is 202C-C56F
Directory of C:\
31-01-2005 12:17 0 test
31-01-2005 12:18 0 test2
2 File(s) 0 bytes
0 Dir(s) 25,673,706,496 bytes free
C:\>type test2
C:\>
==== end capture =====
As you can see no errors were reported, but file was created - but it's
empty. So maybe it would require to test file size, and asume errors where
reported if size is greater than 0?
kind regards,
Bartek
> As you can see no errors were reported, but file was created - but it's
> empty. So maybe it would require to test file size, and asume errors where
> reported if size is greater than 0?
>
> kind regards,
> Bartek
Thanks for the correction Bartek. Usually redirecting only to NUL I
didn't recognize that.
I maybe more successful to sieve the logfile for possible error
messages.
I am surprised Matthias that you did not read the example I wrote.
I guess I did not put enough redundancy into it.
All redirections are handled by the shell - usually cmd.exe - before it
runs the command. I used to have a UNIX notin to get the return code
from the first element of a pipeline. It was clever - not my work. I
can't remember how it worked and am inclined to think it can't be done
with cmd.exe. When I have such a requirement, I usually do something
like "foo > out 2> err" in one "DOS window" and "tail -f foo" in
another. tail is a UNIX utility. "tail -f foo" outputs the last 10 lines
of foo and any more lines written to it. It continues until interrupted.
>
>I maybe more successful to sieve the logfile for possible error
>messages.
>
--
Walter Briscoe
I did read it Walter.
> All redirections are handled by the shell - usually cmd.exe - before it
> runs the command.
Thats only true for redirecting standard input with "<"
When pipes are involved they are "true pipes" established simultaneously
with a second temporary cmd process.
> I used to have a UNIX notin to get the return code from the first
> element of a pipeline.
I don't understand "notin" in this context, the design of the true pipes
maybe arguable - but to no avail.
> It was clever - not my work. I
> can't remember how it worked and am inclined to think it can't be done
> with cmd.exe. When I have such a requirement, I usually do something
> like "foo > out 2> err" in one "DOS window" and "tail -f foo" in
> another. tail is a UNIX utility. "tail -f foo" outputs the last 10 lines
> of foo and any more lines written to it. It continues until interrupted.
>
There are ports of tail available.
But I still don't understand how your first example and this second could
help Don with his problem.
He needs a feedback of the failure to his app. If I understand right,
he wants to have output on screen and in a log file in real time thus
he uses tee. The errorlevel of the app is hidden and I see only the
way to check for an error message. Either in the separated erroroutput
(if supported) or in the log file.
IMO Don should give more details if he still needs help.
@echo off
cmd /v:on /c "dir c:\ /badarg & echo exit /b !ERRORLEVEL! >tmp.bat" | more
call tmp.bat
echo ERRORLEVEL %ERRORLEVEL%
--
tksotn