仅在管道时无法回显右括号

Can't echo close parenthesis only when piping

我有一个非常特殊的问题,echo 写“ECHO is on.”,即使它有一个参数,但只有在打印到管道时,对于某些参数。

我的用例是我正在编写一个脚本文件以提供给解释器。在 Linux 我使用 heredocs 很好地实现了这一点。

prog arg1 - arg3 arg4 \
<< EOM
    start server load (
        foreground
        initial database '$database'
        directory $directory
        from file '${database}.ext'
    );
EOM

对于 Windows' 批次,我最近发现了一些非常相似的东西;

(
    echo start server load ^(
    echo     foreground
    echo     initial database '%%d'
    echo     directory %directory%
    echo     from file '%%d.ext'
    echo ^);
    echo.
) | prog arg1 - arg3 arg4

但我一直收到以下错误:

E7511-ACE: '-' line 6: An error has occurred while processing the DDM file.
Caused by
E2420-ACE: Expected punctuation character ')'.
4:     directory 'C:\Users\redacted\AppData\Local\Temp'
5:     from file 'testing.ext'
6: ECHO is on.
---^---
7:  )

但如果我不情愿地使用临时文件,一切都运行良好!

(
    echo start server load ^(
    echo     foreground
    echo     initial database '%%d'
    echo     directory %directory%
    echo     from file '%%d.ext'
    echo ^);
    echo.
) > tmp.txt
prog arg1 tmp.txt arg3 arg4

tmp.txt 的内容;

start server load (
    foreground
    initial database 'testing'
    directory 'C:\Users\redacted\AppData\Local\Temp'
    from file 'testing.ext'
);

我什至尝试模拟一个 .bat 来尝试展示它,但它所做的只是让我觉得我疯了

@echo off
set databases=a
for %%d in (%databases%) do (
    (
        echo bob ^(
        echo     %%d
        echo ^);
    )
)
pause

输出:

bob (
    a
);
Press any key to continue . . .

我不知道有任何 .exe 接受 stdin 并且只是将它写到 screen/to 一个文件中让我测试我的“管道时它坏了”的假设(Windows' type & echo 不如 Linux' cat & echo),
你们有什么想法吗?

管道是在两个进程之间创建的。管道左侧的代码是批处理代码,因此将启动一个新的 cmd 实例来为管道左侧创建进程,并将代码传递给该实例。

您的转义字符是为当前 cmd 实例正确编写的,但是当代码传递给新实例时,没有转义代码,因为在准备要在新 [= =11=]实例.

您需要双重转义右括号,转义转义字符和转义括号,以便新的 cmd 实例收到正确转义的括号。

(
    echo start server load (
    echo     foreground
    echo     initial database '%%d'
    echo     directory %directory%
    echo     from file '%%d.ext'
    echo ^^^);
    echo.
) | prog arg1 - arg3 arg4

重定向和问题中的 for 代码没有任何问题,因为代码正在当前 cmd 实例中执行。

对于大多数情况,应使用 MC ND(使用三个插入符号)的解决方案。

但是当你想在一行中输出许多特殊字符时,总是添加插入符号会很烦人。

喜欢

(
    echo amp^^^& caret^^^^ single quote^^"
    echo ^^^<html^^^>^^^<body^^^>^^^</body^^^>^^^</html^^^>
) | more

您可以使用引号消失技术。

SET "FOR=FOR /F "tokens=1,2" %%^! IN ("a") DO @("

(
    %%FOR%% ^
    echo %%"amp& caret^ single quote"
    echo %%"<html><body></body></html>%%"
    rem.^)
) |  more

技术本身很复杂,但使用起来很容易。
它使用了这样一个事实,即解析器将看到 %%" 中的引号并将引用以下字符,但稍后它会将 %%" 替换为任何内容。

另一种选择是在脚本中嵌入带有标签前缀(如 :::)的文本,并使用 FINDSTR 提取行。 FOR /F命令可以去掉:::前缀,如果使用延迟扩展可以扩展变量。我假设您的代码已经在某种类型的 FOR 循环中,因为您正在使用 %%d%%d 值必须传输到环境变量,以便它可以正确扩展。我添加了一个伪造的 FOR 循环,这样我就有了一个 %%d 值。

管道命令 运行 在新的 cmd.exe 进程中,因此必须通过带有 /v:on 选项的额外 CMD 命令启用延迟扩展。

@echo off
setlocal

:::start server load (
:::    foreground
:::    initial database '!database!'
:::    directory !directory!
:::    from file '!database!.ext'
:::);

set "directory=c:\test"
for %%d in (test) do (
  set "database=%%d"
  cmd /v:on /c for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"'^) do @echo %%A|prog arg1 - arg3 arg4
)

您可以包含多个具有唯一标签的文本块,只需稍微修改 FINDSTR 和 FOR /F。下面我仍然只有一个文本块,但我展示了如何处理标签。

@echo off
setlocal

::1:start server load (
::1:    foreground
::1:    initial database '!database!'
::1:    directory !directory!
::1:    from file '!database!.ext'
::1:);

set "directory=c:\test"
for %%d in (test) do (
  set "database=%%d"
  cmd /v:on /c for /f "tokens=1* delims=:" %%A in ('findstr "^::1:" "%~f0"'^) do @echo %%B|prog arg1 - arg3 arg4
)

另一种方法是使用LF macro variable将多行值存储在变量中:

@echo off

rem Define \n ("new line") variable:
set LF=^
%empty line 1/2, don't remove%
%empty line 2/2, don't remove%
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"

rem Define your multi-line value:
set multiLine=%\n%
start server load (%\n%
    foreground%\n%
    initial database '%%d'%\n%
    directory %directory%%\n%
    from file '%%d.ext'%\n%
);%\n%


cmd /V:ON /C echo !multiLine! | prog arg1 - arg3 arg4


rem If Delayed Expansion is enabled, use it this way:

setlocal EnableDelayedExpansion
cmd /V:ON /C echo ^^^!multiLine^^^! | prog arg1 - arg3 arg4