Home > Mobile >  Do .bat files terminate when piping an unrecognized command?
Do .bat files terminate when piping an unrecognized command?

Time:09-08

My batch file is prematurely terminating when I run this in a cmd.exe that is NOT an MSVC development command shell.

msbuild /version | find "Microsoft (R) Build Engine version 16" >nul
echo did I get here?
if errorlevel 1 goto no_msbuild

I never get to the if errorlevel line, so I added the echo did I get here? line, and I don't get that either.

Here's the output when I run the .bat file (I removed the @echo off):

Wed 09/07/2022 10:37:49
D:\temp> msbuild /version   | find "Microsoft (R) Build Engine version 16"  1>nul
'msbuild' is not recognized as an internal or external command,
operable program or batch file.

Wed 09/07/2022 10:37:49
D:\temp>

It works fine when I run it in a VS2019 cmd shell (if errorlevel 1 test is false, i.e. errorlevel is 0, so find worked) and a VS2008 cmd (if errorlevel 1 is true, so find failed)

EDIT: I eliminated the whole msbuild command/path issue, incorporating @mofi possible solution and came up with the following:

xyzzy 2>nul | find "abc"
echo hello
if errorlevel 1 goto no_xyzzy

The .bat file still terminates prematurely and never executes the echo hello even with the stderr redirection to nul.

CodePudding user response:

Let me try and simplify this.

xyzz | find... is piping the stdout of xyzz to find. however, xyzz does not exist and therefore does not have stdout or stderr streams, so it will terminate. cmd however will produce 9009 errorlevel, but you did not request stdout or stderr from cmd, you requested it from xyzz becuE you piped it to find

To prove this point, we can eliminate find

xyzz 2>nul
if errorlevel 1 echo Failed
echo %errorlevel%

This will result in a result Failed.

We can however parenthesize the command and pipe the block to find.

(xyzz 2>nul) | find "abc"
if errorlevel 1 echo Failed
echo %errorlevel%

Firstly note, errorlevel is now 1 and not 9009, not because 9009 does not exist, it existed inside the parenthesis, but find is overwriting errorlevel

Then, the reason this works is because the code block in its entirety is redirected to find, that means the cmd result as well, the entire block does not fail, only xyzz does and the execution of the block completes, but now the find query was not met and caused errorlevel 1

you can shorten this test by simply running:

xyzz 2>nul | find "abc" && echo success || echo failed

vs

(xyzz 2>nul) | find "abc" && echo success || echo failed

One last thing. .bat is the old extension of batch-files and it handles errorlevel slightly differently from the new .cmd extensions. So rather use the new normal.

  • Related