It's because of the folding.
Using pipes results in two separate child cmd.exe processes.
But the code has to be folded before it's transferred to a cmd.exe, especially code blocks.
The folding rule is simple, each new line will be translated into an ampersand.
So a folded block looks like
( echo X1 & echo X2 )
But with a REM you get
( REM & echo X4 )
The REM remarks the rest of the line, the ampersand has no effect anymore and the closing parenthesis is also remarked.
If the REM is after that ECHO, it's the same problem
( echo X4 & REM )
The last part is remarked, so there is only ( echo X4
and the closing parenthesis is missing.
But why ::
comments work?
It looks like ::
should result in the same error like REM
, but it works!
It's because ::
labels are completely stripped from a code block, so the resulting line for a block like
(
:: My comment
echo X4
)
Results in simply:
C:\Windows\system32\cmd.exe /S /D /c" ( echo X4 )"
How to make REM work in piped blocks?
The simple way is to use REM.
, but it's no quite a real REM
, it can't comment out ampersand or other special characters.
(
REM. This is a comment, special characters aren't allowed here
echo This works
) | more
Or use an extra line feed in the REM line
(set \n=^
%=THIS LINE IS REQUIRED=%
)
(
REM This is a comment with & and | %%\n%% BREAK
echo This works
) | more
How to debug folded blocks?
It's simple with the cmdcmdline
pseudo variable
(
echo Debug %%cmdcmdline%%%
echo one
echo two
) | findstr /n "^"
Result:
1:Debug C:\Windows\system32\cmd.exe /S /D /c" ( echo Debug
%cmdcmdline% & echo one & echo two )"
2:one
3:two
See also Why does delayed expansion fail when inside a piped block of code?