Batch file 批处理-在带有竖条(";&124quot;)的脚本中调用脚本会导致错误
如果在调用Batch file 批处理-在带有竖条(";&124quot;)的脚本中调用脚本会导致错误,batch-file,cmd,scripting,windows-scripting,Batch File,Cmd,Scripting,Windows Scripting,如果在调用退出1时,脚本应在子例程中退出而不关闭终端。这里我使用if再次调用脚本 这很好,直到我现在发现一个带有引号的竖条作为参数的问题。“!”。我收到一个错误,说明命令拼写错误 以下是脚本中失败的部分: @ECHO OFF SETLOCAL DISABLEDELAYEDEXPANSION IF "%selfWrapped%"=="" ( REM this is necessary so that we can use "exit" to terminate t
退出1
时,脚本应在子例程中退出而不关闭终端。这里我使用if
再次调用脚本
这很好,直到我现在发现一个带有引号的竖条作为参数的问题。“!”
。我收到一个错误,说明命令拼写错误
以下是脚本中失败的部分:
@ECHO OFF
SETLOCAL DISABLEDELAYEDEXPANSION
IF "%selfWrapped%"=="" (
REM this is necessary so that we can use "exit" to terminate the batch file,
REM and all subroutines, but not the original cmd.exe
SET selfWrapped=true
%ComSpec% /s /c ""%~0" %*"
GOTO :EOF
)
echo %*
ENDLOCAL
EXIT /B 0
电话:
预期产出:
"hello world" "|"
我在IF
中检查了%*
的值,但是使用竖线以及任何其他带引号的字符串似乎是完全合法的
所以
我不同意链接中的一些描述。 请参阅
退出/?
准确的帮助说明
退出解释器exit
使用exitcode 1退出解释器exit 1
的行为与退出的exit/b
类似 该脚本或称为标签。Errorlevel未重置,因此允许 可在之后访问上一个命令的errorlevel 退出脚本或被调用的标签goto:eof
以errorlevel 1退出脚本或调用的标签exit/b1
exit/b
,它将退出解释器
主代码:
@ECHO OFF
SETLOCAL DISABLEDELAYEDEXPANSION
SET args=%*
SET "self=%~f0"
IF "%selfWrapped%"=="" (
@REM this is necessary so that we can use "exit" to terminate the batch file,
@REM and all subroutines, but not the original cmd.exe
SET "selfWrapped=true"
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO !ComSpec! /s /c ""!self!" !args!"
"!ComSpec!" /s /c ""!self!" !args!"
GOTO :EOF
)
ECHO(%*
EXIT /B 0
使用GOTO:EOF
和EXIT/b0
都将退出脚本。
ENDLOCAL
隐含在脚本的出口处。
显式使用ENDLOCAL
用于您希望结束
当前本地作用域并继续脚本。像往常一样
始终明确是一种选择
将%*
设置为args
可使双引号保持成对。
引用,即设置“args=%*”
有时会导致问题
虽然不使用引号,但允许代码注入,即。
参数“arg1”^&del*
。如果del*
没有运行
要在set
行执行,则可能会发生这种情况
在ComSpec
行。对于这个例子,我选择了不引用。
因此,这是一种选择
您正在脚本开始时使用禁用的扩展。那个
保存代码>参数,这是好的。在你执行之前
ComSpec
但是,启用延迟扩展并使用!阿格斯代码>
它现在受到保护,不会被解释器看到|
或任何其他可能引发错误的特殊字符
当|
参数暴露时,脚本失败
C:\Windows\system32\cmd.exe /s /c ""test.cmd" " | ""
以上是对ComSpec
行的重复评估
设置@ECHO ON
。注意引号的配对
i、 e.、、、、、。请注意插入的额外间距
绕过<代码> <代码>字符,因为解释程序不考虑
它作为带引号的字符串的一部分
与回显评估的更新代码更改相比…:
"!ComSpec!" /s /c ""!self!" !args!"
引号之间的字符串保持不变。没有额外的间距
插入到字符串中。回响的评估看起来很好,而且
执行良好
免责声明:
@ECHO OFF
SETLOCAL DISABLEDELAYEDEXPANSION
SET args=%*
SET "self=%~f0"
IF "%selfWrapped%"=="" (
@REM this is necessary so that we can use "exit" to terminate the batch file,
@REM and all subroutines, but not the original cmd.exe
SET "selfWrapped=true"
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO !ComSpec! /s /c ""!self!" !args!"
"!ComSpec!" /s /c ""!self!" !args!"
GOTO :EOF
)
ECHO(%*
EXIT /B 0
表达CMD的工作方式就像走钢丝一样。
就在你认为你知道的时候,从绳子上摔下来。我认为没有必要将参数附加到你的%ComSpec%/s/c”“%~0”%*“
由于您已经使用变量(selfWrapped
)来检测,如果需要包装调用,还可以将参数放入变量中
set args=%*
然后您可以简单地使用!阿格斯代码>在您的子实例中
@ECHO OFF
setlocal DisableDelayedExpansion
IF "%selfWrapped%"=="" (
@REM this is necessary so that we can use "exit" to terminate the batch file,
@REM and all subroutines, but not the original cmd.exe
SET "selfWrapped=true"
SET ^"args=%*"
"%ComSpec%" /s /c ""%~f0""
GOTO :EOF
)
:Main
setlocal EnableDelayedExpansion
ECHO(!args!
EXIT /B 0
现在剩下的唯一问题是设置参数=%*
如果无法控制内容,则无法以简单安全的方式访问%*
。
想想这个批处理调用
myBatch.bat“abc|”
myBatch.bat abc^|
myBatch.bat abc^|--“|”
但是你可以使用
或
顺便说一句,您可以腾出子进程,也可以退出函数
查看对上述答案的一处更正。
是的,ENDLOCAL
隐含在脚本末尾,但是有一个陷阱
我发现,对于嵌套脚本,如果在退出/b1之前不执行ENDLOCAL
,则在下一级脚本中将无法获得1
的返回代码
如果您只退出/b0
,那么这并不重要,因为默认返回代码是0
如果您直接运行bat或使用call:“%~0”%*
或调用“%~0”%*
可以吗:%ComSpec%”/S/C“%~0”%*
?@Squashman,如备注中所述,新的cmd
实例需要能够使用exit
终止批处理脚本及其所有子例程,因此,当前实例不会变为quit…这是怎么回事:%ComSpec%”/S/C^^^^“%~0”%*^^^^“
,甚至是%ComSpec%”/S/C^^^^^“%~0“%
?看看Jeb和Dbenham对这个问题的看法会很有趣。他们对解析规则非常了解。不错,但是考虑到延迟扩展只在父cmd
实例中有帮助,而在子实例中没有帮助!无论如何,仍有改进的余地:1。当启用延迟扩展时,您正在扩展%
-变量,这可能会导致问题,尤其是的问题代码>字符;将所有%
扩展更改为代码>要安全的代码(如!ComSpec!
;然后在启用延迟扩展之前执行设置“self=%~0F”
,并使用!self!
而不是以后使用%~f0
)。2.放!通信规范
介于之间“
允许自定义系统目录包含空格。3.使用安全的echo
语法echo(%*
.4.I