Pau*_*ban 12 cmd escaping batch-file caret
我有一个Windows CMD脚本,它接受许多参数并执行EXE,首先传递一些硬编码参数,然后传递用户的所有参数.CMD脚本如下所示:
launcher.exe paramX paramY %*
Run Code Online (Sandbox Code Playgroud)
用户将从Windows shell执行CMD脚本,如下所示:
launcher.cmd param1 param2 param3 [...]
Run Code Online (Sandbox Code Playgroud)
我的问题是,如果参数到CMD脚本包含壳等特殊字符< >和^,用户被迫通过前述各用3插入符号逸出这些^壳转义字符.
1)要将参数传递ten>one给EXE,用户必须按如下方式启动CMD:
launcher.cmd ten^^^>one
Run Code Online (Sandbox Code Playgroud)
这样做的原因是,shell特殊字符^,并>通过命令外壳在两个层面解释,首先在命令行和第二的CMD脚本中.因此,使用脱字符^外壳转义字符转义的shell必须应用两次.问题是这对用户来说并不明显,看起来很难看.
对于这个例子,一个更好的解决方案是用双引号括起参数.但是,这会分解为更复杂的示例,其中包含参数中的文字双引号.
2)要将参数传递"^给EXE,用户必须按如下方式启动CMD:
launcher.cmd "\"^^^^"
Run Code Online (Sandbox Code Playgroud)
在我的情况下,我想支持包含任何低ASCII字符序列的参数,不包括控制字符,即代码点0x20到0x7E.我知道会有一些例子,用户必须使用插入符号来逃避某些shell特殊字符.但是,我不希望用户在这些情况下每次都必须使用3个插入符,因为它们恰好是在调用CMD脚本而不是EXE.
我可以通过使用执行相同操作的EXE替换CMD脚本来解决此问题.但是,有没有办法改变CMD脚本,以便它将参数传递给EXE而不解释shell特殊字符?
一种方法是在批处理中使用延迟扩展,因为那时特殊字符失去了"特殊"含义.
唯一的问题是将参数放入变量中.
这样的事情可能会有所帮助
@echo off
setlocal DisableDelayedExpansion
rem ** At this point the delayedExpansion should be disabled
rem ** otherwise an exclamation mark in %1 can remove carets
set "param1=%~1"
setlocal EnableDelayedExpansion
rem ** Now you can use the param1, independent of the content, even with carets or quotes
rem ** but be careful with call's, because they start a second round of expansion
echo !param1!
set "tmp=!param1:~1,4!"
Run Code Online (Sandbox Code Playgroud)
现在参数可以用引号括起来,所以不再需要插入符号.示例launcher.bat"abc> def&geh%ijk | lmn ^ opq!"
唯一剩下的有问题的特殊字符似乎是引号.
[编辑/改进]我创建另一种方法来检索参数,我认为它也可以接受任何字符串也是你的第二个例子.
即使是非常难的字符串
发射器"^
launcher ten ^> one
launcher"&"^&
@echo off
setlocal DisableDelayedExpansion
set "prompt=X"
for %%a in (1 ) do (
@echo on
for %%b in (4) do (
rem #%1#
)
) > XY.txt
@echo off
for /F "delims=" %%a in (xy.txt) DO (
set "param=%%a"
)
setlocal EnableDelayedExpansion
set param=!param:~7,-4!
echo param='!param!'
Run Code Online (Sandbox Code Playgroud)
这个怎么运作?
我发现扩展%1而不扩展特殊字符(如"或^")的唯一方法是在REM语句中(对于REM来说,这不是完全正确的,但这是另一个故事)好的,唯一的问题是REM是一个评论并没有效果:-)
但是如果你使用echo也会在它们执行之前回显 rem线(执行rem是一个很好的词).
下一个问题是显示它,您无法使用normal> debug.txt 重定向此调试输出.如果使用for循环也是如此.
好的,您可以通过类似的调用重定向输出上 的回显
echo on
call :myFunc > debug.txt
Run Code Online (Sandbox Code Playgroud)
但是,如果您调用函数,则无法再访问批处理文件的%1.
但是使用双重for循环,可以激活调试输出的重定向,并且仍然可以访问%1.
我将提示改为"X",所以我知道它总是只有一个字符.
唯一剩下的就是解释为什么我将#追加到%1.
那是因为,某些特殊字符在某些情况下甚至在REM线中都被识别出来,显然;-)
rem This is a remark^
rem This_is_a_multiline^
rem "This is also a multiline"^
Run Code Online (Sandbox Code Playgroud)
所以#抑制了可能的多线情况.
这有帮助吗:
EscapPipes.Cmd:
@echo off
:Start
If [%1]==[] goto :eof
@Echo %1
shift
goto :Start
Run Code Online (Sandbox Code Playgroud)
当开始时:
EscapPipes.Cmd Andy Pandy "Pudding | > < and pie"
Run Code Online (Sandbox Code Playgroud)
给出
Andy
Pandy
"Pudding | > < and pie"
Run Code Online (Sandbox Code Playgroud)
一旦您去掉引号,管道符号就会变为活动状态。
| 归档时间: |
|
| 查看次数: |
18938 次 |
| 最近记录: |