Actually, the parentheses do make a surprising difference in the presence of a pipe - something that I have never seen before.
I was mistaken in my earlier code in that the & and > did not need to be escaped because the parentheses are present. The following will work just fine:
Code: Select all
(boguscmd & >err.tmp call echo %%^^errorlevel%%) | tee tmp1.txt
set /p "leftErr=" <err.tmp
del err.tmp
echo leftErr=%leftErr%
The following without parentheses or escaping does not work because only the CALL ECHO is piped; BOGUSCMD is not piped.
Code: Select all
boguscmd & >err.tmp call echo %%^^errorlevel%%) | tee tmp1.txt
But there is an additional subtle difference.
Without parentheses, it should be possible to work without parentheses if you escape the & and > so that the batch parser only sees a single command to be piped. I will first demonstrate with a valid command to show what I mean.
First, I'll create a simple batch script that puts out a line of output and exits with an error:
err.batCode: Select all
@echo off
echo This script generates an error.
exit /b 1
The following works fine:
Code: Select all
@echo off
setlocal
err.bat ^& call echo %%^^errorlevel%% ^>err.tmp | findstr /n "^"
set /p "leftErr=" <err.tmp
del err.tmp
echo leftErr=%leftErr%
--OUTPUT--
Code: Select all
1:This script generates an error.
leftErr=1
The 1: prefix proves that the left side was piped properly, and the leftErr value proves the error was properly captured.
But if I substitute an invalid command, then the pipe is never executed, and the batch script is terminated
Code: Select all
@echo off
setlocal
boguscmd ^& ^>err.tmp call echo %%^^errorlevel%% ^& echo OK | findstr /n "^"
set /p "leftErr=" <err.tmp
del err.tmp
echo leftErr=%leftErr%
--OUTPUT--
Code: Select all
'boguscmd' is not recognized as an internal or external command,
operable program or batch file.
If I add parentheses, then all is well. Note that I preserved the escapes to show that it is just the parentheses that have changed. But they aren't really needed.
Code: Select all
@echo off
setlocal
(boguscmd ^& ^>err.tmp call echo %%^^errorlevel%% ^& echo OK) | findstr /n "^"
set /p "leftErr=" <err.tmp
del err.tmp
echo leftErr=%leftErr%
--OUTPUT--
Code: Select all
'boguscmd' is not recognized as an internal or external command,
operable program or batch file.
1:OK
leftErr=9009
What is going on here
I cannot arrive at a rational reason for this behavior. Without parentheses, it seems as if the batch parser recognizes that the command is invalid, so it never executes the pipe. I can just about accept this. But I cannot understand why the pipe causes the invalid command to be treated as a fatal error. Without the pipe, the the error message is simply printed and the script continues.
For some unknown reason, adding the parentheses delays detection of the invalid command, the pipe works, and everything works as expected.
I know of one other case where parentheses change the behavior of a pipe - the parentheses prevent delayed expansion in the presence of a pipe. See
http://stackoverflow.com/q/8192318/1012053 for more info.
Dave Benham