为什么 rem 会影响通过管道输出的代码块?

ber*_*ers 4 windows comments pipeline batch-file

more我喜欢使用括号中的命令块,因为它允许我立即将块中所有命令的输出通过管道传输到(或任何其他命令)。

通常,我也可以在这些块内添加注释(rem)。

但是,我似乎无法将这两个功能结合起来:带有注释的块more(或任何其他命令)根本不被执行。这是为什么?能解决吗?

@echo off
rem This works (prints X1)
(
    echo X1
)

rem This works (prints X2)
(
    echo X2
) | more

rem This works (prints X3)
(
    rem
    echo X3
)

rem Why does this print nothing?
(
    rem
    echo X4
) | more

rem Or this?
(
    echo X4
    rem
) | more

rem This works (prints X5)
(
    :: Using colons instead of rem
    echo X5
) | more
Run Code Online (Sandbox Code Playgroud)

jeb*_*jeb 6

就是因为折叠了
使用管道会产生两个单独的子 cmd.exe 进程。
但代码在传输到 cmd.exe 之前必须折叠,尤其是代码块。

折叠规则很简单,每一行都会被翻译成一个&符号。
所以折叠块看起来像

( echo X1 & echo X2 )
Run Code Online (Sandbox Code Playgroud)

但是通过快速眼动你会得到

( REM & echo X4 ) 
Run Code Online (Sandbox Code Playgroud)

REM 注释了该行的其余部分,& 符号不再起作用,并且还注释了右括号。

如果 REM 是在 ECHO 之后,也是同样的问题

( echo X4 & REM ) 
Run Code Online (Sandbox Code Playgroud)

最后一部分已被注释,因此只有( echo X4并且缺少右括号。

但为什么::评论会起作用呢?
看起来::应该会导致与 相同的错误REM,但它有效!
这是因为::标签完全从代码块中剥离,因此像这样的块的结果行

( 
  :: My comment
  echo X4
)
Run Code Online (Sandbox Code Playgroud)

结果很简单:

C:\Windows\system32\cmd.exe  /S /D /c" ( echo X4 )"
Run Code Online (Sandbox Code Playgroud)

如何让 REM 在管道块中工作?

简单的方法是使用REM.,但它不是一个真正的REM,它不能注释掉&符号或其他特殊字符。

( 
  REM. This is a comment, special characters aren't allowed here
  echo This works
) | more
Run Code Online (Sandbox Code Playgroud)

或者在 REM 行中使用额外的换行符

(set \n=^
%=THIS LINE IS REQUIRED=%
)
( 
  REM This is a comment with & and | %%\n%% BREAK
  echo This works
) | more
Run Code Online (Sandbox Code Playgroud)

如何调试折叠块?

cmdcmdline使用伪变量很简单

(
  echo Debug %%cmdcmdline%%%
  echo one
  echo two
) | findstr /n "^"
Run Code Online (Sandbox Code Playgroud)

结果:

1:调试 C:\Windows\system32\cmd.exe /S /D /c" ( echo Debug %cmdcmdline% & echo one & echo 2 )"
2:一
3:二

另请参阅为什么在管道代码块内延迟扩展会失败?