我有一个非常特殊的问题,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
),
你们有什么想法吗?
答案 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