Windows批处理延迟扩展在运行管道时中断

ao218c7q  于 2023-03-09  发布在  Windows
关注(0)|答案(2)|浏览(153)

在一个. bat脚本中,我有一个包含&的变量,需要传递给多个命令,其中一个命令是pipe。

set foo="1 & 2"
command1 --foo %foo% --bar
echo %foo% | command2 --stdin

在尝试了herehere中的各种解决方案之后,我最终将变量的值用引号括起来(而不是转义而不加引号,或者将整个"var = value"用引号括起来)。
这在向命令传递参数时有效;但在管道中使用echo时,引号也会传递给stdin:

setlocal enableExtensions enableDelayedExpansion
set foo="1 & 2"

echo %foo% | sort

输出(如预期):

"1 & 2"

接下来,我添加了延迟扩展以删除引号,但是现在管道符在echo中变成了一个文本字符,而不是同时运行两个命令:

setlocal enableExtensions enableDelayedExpansion
set foo="1 & 2"

echo !foo:"=! | sort

输出:
如何说服脚本实际运行管道,而不是将其变成一个文本字符串?
为了以防万一,我在Windows 10中运行此程序。

  • 注意 *:上面使用的sort只是一个任意命令的例子,它很方便,因为它获取stdin并将其打印出来,类似于Linux中的cat命令。
lyr7nygr

lyr7nygr1#

正如Stephan所说,双方都在自己的子进程中执行,这导致了多次解析命令。
你可以通过多次转义来解决它,或者你可以构建一个命令,不需要转义。
一种方法是避免在批处理文件本身中展开,并且只使用一个转义级别。
喜欢

set "foo=1 ^& 2"
echo %%foo%% | sort

在批处理文件和子进程中将解析双百分比,它变为:

echo %foo%

在子进程中使用 late 延迟扩展甚至更好,但有点棘手,因为子进程将在没有启用延迟扩展的情况下启动(注册表项HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion中的默认值为0x 00/OFF),您需要使用一个额外的cmd.exe进程启用它。

set "foo=1 & 2"
(cmd /V:on /C "echo !foo!") | sort

圆括号避免了批处理文件本身的延迟扩展。
或者对于更复杂的内容,可能在左侧包含IF或FOR循环,我建议在子进程中启动批处理文件本身。
在我的例子中,我使用了蹦床技术。

@echo off
REM *** Trampoline jump for function calls of the form ex. "C:\:function:\..\MyBatchFile.bat"
FOR /F "tokens=3 delims=:" %%L in ("%~0") DO goto :%%L

set "foo[0]=5 & 6"
set "foo[1]=7 ! >>"
set "foo[2]=8"
set "foo[3]=9%%"
"%~d0\:childProc:\..\%~pnx0" | sort
exit /b

:childProc
setlocal enabledelayedExpansion
for /L %%n in (0 1 3) do echo(!foo[%%n]!
exit /b
jtw3ybtb

jtw3ybtb2#

由于管道的两端是在不同的进程中执行的,因此需要对有害字符进行“双转义”(并对其中一个转义字符也进行转义,以便将其传递给第二个示例),这样就产生了 * 三个 * 转义字符:

setlocal enableExtensions enableDelayedExpansion
set "foo=1 & 2"
echo %foo:&=^^^&% | sort
rem or:
set "foo=1 ^^^& 2"
echo %foo% | sort

相关问题