仅在管道时无法回显右括号
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
我有一个非常特殊的问题,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