只有在管道时才能回显紧密的括号

时间:2015-04-13 08:07:51

标签: windows batch-file cmd pipe echo

我有一个非常特殊的问题,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只是把它写到屏幕上/文件中供我测试'它在管道'假设时坏了(Windows'{ {1}}&amp; type的功能不如Linux echo&amp; cat),
你们有什么想法吗?

4 个答案:

答案 0 :(得分:3)

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

为当前cmd实例正确编写了转义字符,但是当代码传递给新实例时,没有转义代码,因为在准备要在新{{1实例。

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

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实例中执行。

答案 1 :(得分:2)

对于大多数情况,应使用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

技术本身很复杂,但使用它很容易 它使用以下事实:解析器将在%%"中看到引号,并引用以下字符,但稍后它将替换%%"

答案 2 :(得分:1)

另一种选择是使用标签前缀:::在脚本中嵌入文本,并使用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
)

答案 3 :(得分:1)

另一种方法是使用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