Smart猫小萌
我不确定我是应该编辑我的问题,还是把它作为答案发布。我已经模糊地知道,管道在自己的cmd.exe“会话”中同时执行左侧和右侧。但是Aacini和Jeb的回答迫使我认真思考和调查管道的情况。(感谢Jeb演示了当管道进入SET/P时发生了什么!)我开发了这个调查脚本-它帮助解释了很多,但也演示了一些奇怪和意外的行为。我将发布脚本,然后是输出。最后,我将提供一些分析。@echo off
cls
setlocal disableDelayedExpansion
set var1=value1
set "var2="
setlocal enableDelayedExpansion
echo on
@echo NO PIPE - delayed expansion is ON
echo 1: %var1%, %var2%, !var1!, !var2!
(echo 2: %var1%, %var2%, !var1!, !var2!)
@echo(
@echo PIPE LEFT SIDE - Delayed expansion is ON
echo 1L: %%var1%%, %%var2%%, !var1!, !var2! | more
(echo 2L: %%var1%%, %%var2%%, !var1!, !var2!) | more
(setlocal enableDelayedExpansion & echo 3L: %%var1%%, %%var2%%, !var1!, !var2!) | more
(cmd /v:on /c echo 4L: %%var1%%, %%var2%%, !var1!, !var2!) | more
cmd /v:on /c echo 5L: %%var1%%, %%var2%%, !var1!, !var2! | more
@endlocal
@echo(
@echo Delayed expansion is now OFF
(cmd /v:on /c echo 6L: %%var1%%, %%var2%%, !var1!, !var2!) | more
cmd /v:on /c echo 7L: %%var1%%, %%var2%%, !var1!, !var2! | more
@setlocal enableDelayedExpansion
@echo(
@echo PIPE RIGHT SIDE - delayed expansion is ON
echo junk | echo 1R: %%var1%%, %%var2%%, !var1!, !var2!
echo junk | (echo 2R: %%var1%%, %%var2%%, !var1!, !var2!)
echo junk | (setlocal enableDelayedExpansion & echo 3R: %%var1%%, %%var2%%, !var1!, !var2!)
echo junk | (cmd /v:on /c echo 4R: %%var1%%, %%var2%%, !var1!, !var2!)
echo junk | cmd /v:on /c echo 5R: %%var1%%, %%var2%%, !var1!, !var2!
@endlocal
@echo(
@echo Delayed expansion is now OFF
echo junk | (cmd /v:on /c echo 6R: %%var1%%, %%var2%%, !var1!, !var2!)
echo junk | cmd /v:on /c echo 7R: %%var1%%, %%var2%%, !var1!, !var2!这是输出NO PIPE - delayed expansion is ON
C:\test>echo 1: value1, , !var1!, !var2!
1: value1, , value1,
C:\test>(echo 2: value1, , !var1!, !var2! )
2: value1, , value1,
PIPE LEFT SIDE - Delayed expansion is ON
C:\test>echo 1L: %var1%, %var2%, !var1!, !var2! | more
1L: value1, %var2%, value1,
C:\test>(echo 2L: %var1%, %var2%, !var1!, !var2! ) | more
2L: value1, %var2%, !var1!, !var2!
C:\test>(setlocal enableDelayedExpansion & echo 3L: %var1%, %var2%, !var1!, !var2! ) | more
3L: value1, %var2%, !var1!, !var2!
C:\test>(cmd /v:on /c echo 4L: %var1%, %var2%, !var1!, !var2! ) | more
4L: value1, %var2%, value1, !var2!
C:\test>cmd /v:on /c echo 5L: %var1%, %var2%, !var1!, !var2! | more
5L: value1, %var2%, value1,
Delayed expansion is now OFF
C:\test>(cmd /v:on /c echo 6L: %var1%, %var2%, !var1!, !var2! ) | more
6L: value1, %var2%, value1, !var2!
C:\test>cmd /v:on /c echo 7L: %var1%, %var2%, !var1!, !var2! | more
7L: value1, %var2%, value1, !var2!
PIPE RIGHT SIDE - delayed expansion is ON
C:\test>echo junk | echo 1R: %var1%, %var2%, !var1!, !var2!
1R: value1, %var2%, value1,
C:\test>echo junk | (echo 2R: %var1%, %var2%, !var1!, !var2! )
2R: value1, %var2%, !var1!, !var2!
C:\test>echo junk | (setlocal enableDelayedExpansion & echo 3R: %var1%, %var2%, !var1!, !var2! )
3R: value1, %var2%, !var1!, !var2!
C:\test>echo junk | (cmd /v:on /c echo 4R: %var1%, %var2%, !var1!, !var2! )
4R: value1, %var2%, value1, !var2!
C:\test>echo junk | cmd /v:on /c echo 5R: %var1%, %var2%, !var1!, !var2!
5R: value1, %var2%, value1,
Delayed expansion is now OFF
C:\test>echo junk | (cmd /v:on /c echo 6R: %var1%, %var2%, !var1!, !var2! )
6R: value1, %var2%, value1, !var2!
C:\test>echo junk | cmd /v:on /c echo 7R: %var1%, %var2%, !var1!, !var2!
7R: value1, %var2%, value1, !var2!我测试了管道的左侧和右侧,以证明处理是对称的。测试1和2表明,在正常批处理情况下,括号对延迟扩展没有任何影响。测试1L,1R:延迟扩张如预期一样有效。Var2是未定义的,所以%var2%和!var2!输出显示这些命令是在命令行上下文中执行的,而不是在批处理上下文中执行的。换句话说,使用命令行解析规则代替批处理解析。(见Windows命令解释器(cmd.exe)如何解析脚本?) 编辑-!VAR 2!在父批处理上下文中展开。测试2L,2R:括号禁用延迟扩展!我心里很奇怪也很意外。编辑-Jeb认为这是一个MS错误或设计缺陷。我同意,不一致的行为似乎没有任何合理的理由测试3L,3R: setlocal EnableDelayedExpansion不起作用。但这是预期的,因为我们处于命令行上下文中。setlocal只在批处理上下文中工作。测试4L,4R:延迟扩展最初启用,但括号禁用它。CMD /V:ON重新启用延迟扩展,一切都按预期进行。我们仍然有命令行上下文,输出和预期的一样。测试5L,5R:几乎与4L一样,除了延迟扩展之外,在以下情况下已启用了4R:CMD /V:on被处决了。%var2%提供预期的命令行上下文输出。但是!变了!输出为空白,这在批处理上下文中是预期的。这是另一个非常奇怪和意外的行为。编辑-实际上这是有意义的,现在我知道了!变种2!在父批处理上下文中展开。测试6L,6R,7L,7R:这些类似于测试4L/R,5L/R,除了现在延迟扩展开始禁用。这一次,所有4种场景都给出了预期的!var2!批处理上下文输出。如果有人能为2L,2R和5L,5R的结果提供一个合乎逻辑的解释,那么我将选择它作为我最初问题的答案。否则,我可能会接受这个帖子作为答案(实际上更多的是观察发生了什么,而不是回答)。刺死它了!增编:作为对Jeb的评论的回应,这里有更多的证据表明,在命令行上下文中,而不是在批处理上下文中,命令在批处理中执行。这个批处理脚本:@echo on
call echo batch context %%%%
call echo cmd line context %%%% | more给出这个输出:C:\test>call echo batch context %%
batch context %
C:\test>call echo cmd line context %% | more
cmd line context %%最后增编我增加了一些额外的测试和结果,以证明到目前为止的所有发现。我还演示了可变膨胀发生在管道处理之前。最后,我展示了管道处理的一些有趣的副作用,当多行块被折叠成一行时。@echo off
cls
setlocal disableDelayedExpansion
set var1=value1
set "var2="
setlocal enableDelayedExpansion
echo on
@echo(
@echo Delayed expansion is ON
echo 1: %%, %%var1%%, %%var2%%, !var1!, ^^^!var1^^^!, !var2!, ^^^!var2^^^!, %%cmdcmdline%% | more
(echo 2: %%, %%var1%%, %%var2%%, !var1!, ^^^!var1^^^! !var2!, %%cmdcmdline%%) | more
for %%a in (Z) do (echo 3: %%a %%, %%var1%%, %%var2%%, !var1!, ^^^!var1^^^! !var2!, %%cmdcmdline%%) | more
(
echo 4: part1
set "var2=var2Value
set var2
echo "
set var2
)
(
echo 5: part1
set "var2=var2Value
set var2
echo "
set var2
echo --- begin cmdcmdline ---
echo %%cmdcmdline%%
echo --- end cmdcmdline ---
) | more
(
echo 6: part1
rem Only this line remarked
echo part2
)
(
echo 7: part1
rem This kills the entire block because the closing ) is remarked!
echo part2
) | more这是输出Delayed expansion is ON
C:\test>echo 1: %, %var1%, %var2%, !var1!, ^!var1^!, !var2!, ^!var2^!, %cmdcmdline% | more
1: %, value1, %var2%, value1, !var1!, , !var2!, C:\Windows\system32\cmd.exe /S /D /c" echo 1: %, %var1%, %var2%, value1, !var1!, , !var2!, %cmdcmdline% "
C:\test>(echo 2: %, %var1%, %var2%, !var1!, ^!var1^! !var2!, %cmdcmdline% ) | more
2: %, value1, %var2%, !var1!, !var1! !var2!, C:\Windows\system32\cmd.exe /S /D /c" ( echo 2: %, %var1%, %var2%, !var1!, ^!var1^! !var2!, %cmdcmdline% )"
C:\test>for %a in (Z) do (echo 3: %a %, %var1%, %var2%, !var1!, ^!var1^! !var2!, %cmdcmdline% ) | more
C:\test>(echo 3: Z %, %var1%, %var2%, !var1!, ^!var1^! !var2!, %cmdcmdline% ) | more
3: Z %, value1, %var2%, !var1!, !var1! !var2!, C:\Windows\system32\cmd.exe /S /D /c" ( echo 3: Z %, %var1%, %var2%, !var1!, ^!var1^! !var2!, %cmdcmdline% )"
C:\test>(
echo 4: part1
set "var2=var2Value
set var2
echo "
set var2
)
4: part1
var2=var2Value
"
var2=var2Value
C:\test>(
echo 5: part1
set "var2=var2Value
set var2
echo "
set var2
echo --- begin cmdcmdline ---
echo %cmdcmdline%
echo --- end cmdcmdline ---
) | more
5: part1
var2=var2Value & set var2 & echo
--- begin cmdcmdline ---
C:\Windows\system32\cmd.exe /S /D /c" ( echo 5: part1 & set "var2=var2Value
var2=var2Value & set var2 & echo
" & set var2 & echo --- begin cmdcmdline --- & echo %cmdcmdline% & echo --- end cmdcmdline --- )"
--- end cmdcmdline ---
C:\test>(
echo 6: part1
rem Only this line remarked
echo part2
)
6: part1
part2
C:\test>(echo %cmdcmdline% & (
echo 7: part1
rem This kills the entire block because the closing ) is remarked!
echo part2
) ) | more测试1:2:总结所有的行为,%cmdcmdline%技巧确实有助于演示正在发生的事情。测试3:演示变量展开仍然适用于管道块。测试4:/5:和6:/7:显示管道与多行块的工作方式的有趣的副作用。小心!我必须相信,在复杂的管道场景中找出转义序列将是一场噩梦。