There is a very simple solution. But to understand it, you must first understand the source of the problem. (jeb already knows this, as he explained it to me)
As explained by the link that jeb provided, each side of the pipe is executed via
CMD /C "command(s) here". So each side of the pipe must be parsed and packaged into a form that will work within the
/C argument to
CMD.EXE. Unfortunately, the batch parser introduces an unwanted space before each
&. This can be seen by ECHOing the
%CMDCMDLINE% value as part of the command. CMDCMDLINE is a dynamic variable that shows the command line passed to CMD.EXE. I use
FINDSTR "^" to simply parrot the output of the left side of the pipe.
Code: Select all
@echo off
(
echo abc
echo def
echo %%cmdcmdline%%)|findstr "^"
) || findstr "^"
-- OUTPUT --
Code: Select all
abc
def
C:\Windows\system32\cmd.exe /S /D /c" ( echo abc & echo def & echo %cmdcmdline% )"
Perhaps surprisingly, the following form with everything on the same line gives the exact same result.
Code: Select all
@echo off
(echo abc&echo def&echo %%cmdcmdline%%)|findstr "^"
--OUTPUT--
Code: Select all
abc
def
C:\Windows\system32\cmd.exe /S /D /c" ( echo abc & echo def & echo %cmdcmdline% )"
The solution is to somehow avoid parsing of the commands before they are embedded in the
/C argument. One way is to explicitly use our own CMD /C command
The parser that packages up the commands only sees a single command. The commands we want are safely embedded in a quoted string argument that does not get modified.
Code: Select all
cmd /c "echo abc&echo def" | xxd -p
But there is an even simpler solution.
Code: Select all
echo off
echo abc^&echo def| xxd -p
Note that it is critical that there not be any space before the pipe symbol.
But perhaps it is not obvious why this works
When the parser sees only one command as part of a pipe, it does not introduce any extra space. The ambersand is escaped, so it is taken as a literal, and the parser sees only a single ECHO command. But the escape is consumed, so the
/C argument becomes
"echo abc&echo def", and all is good.
This can be seen by employing the CMDCMDLINE trick again.
Code: Select all
@echo off
echo abc^&echo def^&echo %%cmdcmdline%%|findstr "^"
--OUTPUT--
Code: Select all
abc
def
C:\Windows\system32\cmd.exe /S /D /c" echo abc&echo def&echo %cmdcmdline%"
Dave Benham