批处理 - 在带有竖线(“|”)的脚本中调用脚本会导致错误
Batch - Call script inside script with vertical bar ("|") causes error
如果一个脚本在调用 EXIT 1
时应该在子例程中退出而不关闭终端。我在那里使用 this 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
致电:
test.cmd "hello world" "|"
预期输出:
"hello world" "|"
我检查了 IF
中 %*
的值,但是使用竖线和任何其他带引号的字符串似乎完全合法。
所以...
- 为什么脚本会失败?
- 我该如何解决?
我不同意link中的一些描述。
请参阅 exit /?
准确的帮助说明。
exit
退出解释器。
exit 1
以退出代码 1 退出解释器。
exit /b
与 goto :eof
具有相似的行为
脚本或称为标签。 Errorlevel 未重置,因此允许
errorlevel 从上一个命令之后可以访问
退出脚本或调用的标签。
exit /b 1
以 errorlevel 1. 退出脚本或调用的标签
如果您在 CMD 提示符下奇怪地使用 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 /B 0
都会退出脚本。
ENDLOCAL
隐含在脚本退出时。
明确使用 ENDLOCAL
是为了当你想结束
当前本地范围并继续脚本。一如既往,被
一直显式是一个选择。
将 %*
设置为 args
可使双引号成对出现。
引用即 set "args=%*"
有时会导致问题
虽然不使用引号允许代码注入,即
参数 "arg1" ^& del *.*
。如果 del *.*
不去
在 set
行执行,那么它可能会发生
在 ComSpec
行。对于这个例子,我选择不引用。
所以,这是一个选择。
您在脚本开始时使用了禁用的扩展。那
保存 !
参数,这很好。在你执行之前
ComSpec
但是,启用延迟扩展并使用 !args!
现在不受解释器的保护,现在看不到 |
或任何其他可能引发错误的特殊字符。
您的脚本失败,因为 |
参数已暴露。
C:\Windows\system32\cmd.exe /s /c ""test.cmd" " | ""
以上是对 ComSpec
行的回应评估
设置 @ECHO ON
。注意引号的配对
即 ""
、" "
和 ""
。注意插入的额外间距
|
字符周围,因为解释器不考虑
它作为引用字符串的一部分。
与回显评估的更新代码更改相比...:
"!ComSpec!" /s /c ""!self!" !args!"
引号之间的字符串保持不变。没有多余的间距
插入到字符串中。回声评价看起来不错
执行得很好。
免责声明:
表达CMD的工作原理就像走钢丝一样。
就在你认为你知道的时候,从绳子上掉下来。
我认为根本没有必要将参数附加到您的 %ComSpec% /s /c ""%~0" %*"
。
由于您已经使用变量(selfWrapped
)进行检测,如果需要包装器调用,您也可以将参数放入变量中。
set args=%*
然后您可以简单地在您的子实例中使用 !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
现在剩下的唯一问题是set args=%*
。
如果您无法控制内容,则无法以简单安全的方式访问 %*
。
想想这批调用
myBatch.bat "abc|"
myBatch.bat abc^|
myBatch.bat abc^|--"|"
但是你可以使用 How to receive even the strangest command line parameters?
或 Get arguments without temporary file
顺便说一句。你可以节省你的子进程,你也可以退出一个函数
看看Exit batch script from inside a function
对以上答案的一个更正。
是的,ENDLOCAL
隐含在脚本末尾,但有一个问题。
我发现对于嵌套脚本,如果您在 EXIT /B 1
之前不 ENDLOCAL
,您将不会在下一级脚本。
如果您只 EXIT /B 0
,那么这无关紧要,因为默认的 return 代码是 0
。
如果一个脚本在调用 EXIT 1
时应该在子例程中退出而不关闭终端。我在那里使用 this 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
致电:
test.cmd "hello world" "|"
预期输出:
"hello world" "|"
我检查了 IF
中 %*
的值,但是使用竖线和任何其他带引号的字符串似乎完全合法。
所以...
- 为什么脚本会失败?
- 我该如何解决?
我不同意link中的一些描述。
请参阅 exit /?
准确的帮助说明。
exit
退出解释器。exit 1
以退出代码 1 退出解释器。exit /b
与goto :eof
具有相似的行为 脚本或称为标签。 Errorlevel 未重置,因此允许 errorlevel 从上一个命令之后可以访问 退出脚本或调用的标签。exit /b 1
以 errorlevel 1. 退出脚本或调用的标签
如果您在 CMD 提示符下奇怪地使用 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 /B 0
都会退出脚本。
ENDLOCAL
隐含在脚本退出时。
明确使用 ENDLOCAL
是为了当你想结束
当前本地范围并继续脚本。一如既往,被
一直显式是一个选择。
将 %*
设置为 args
可使双引号成对出现。
引用即 set "args=%*"
有时会导致问题
虽然不使用引号允许代码注入,即
参数 "arg1" ^& del *.*
。如果 del *.*
不去
在 set
行执行,那么它可能会发生
在 ComSpec
行。对于这个例子,我选择不引用。
所以,这是一个选择。
您在脚本开始时使用了禁用的扩展。那
保存 !
参数,这很好。在你执行之前
ComSpec
但是,启用延迟扩展并使用 !args!
现在不受解释器的保护,现在看不到 |
或任何其他可能引发错误的特殊字符。
您的脚本失败,因为 |
参数已暴露。
C:\Windows\system32\cmd.exe /s /c ""test.cmd" " | ""
以上是对 ComSpec
行的回应评估
设置 @ECHO ON
。注意引号的配对
即 ""
、" "
和 ""
。注意插入的额外间距
|
字符周围,因为解释器不考虑
它作为引用字符串的一部分。
与回显评估的更新代码更改相比...:
"!ComSpec!" /s /c ""!self!" !args!"
引号之间的字符串保持不变。没有多余的间距 插入到字符串中。回声评价看起来不错 执行得很好。
免责声明:
表达CMD的工作原理就像走钢丝一样。 就在你认为你知道的时候,从绳子上掉下来。
我认为根本没有必要将参数附加到您的 %ComSpec% /s /c ""%~0" %*"
。
由于您已经使用变量(selfWrapped
)进行检测,如果需要包装器调用,您也可以将参数放入变量中。
set args=%*
然后您可以简单地在您的子实例中使用 !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
现在剩下的唯一问题是set args=%*
。
如果您无法控制内容,则无法以简单安全的方式访问 %*
。
想想这批调用
myBatch.bat "abc|"
myBatch.bat abc^|
myBatch.bat abc^|--"|"
但是你可以使用 How to receive even the strangest command line parameters?
或 Get arguments without temporary file
顺便说一句。你可以节省你的子进程,你也可以退出一个函数
看看Exit batch script from inside a function
对以上答案的一个更正。
是的,ENDLOCAL
隐含在脚本末尾,但有一个问题。
我发现对于嵌套脚本,如果您在 EXIT /B 1
之前不 ENDLOCAL
,您将不会在下一级脚本。
如果您只 EXIT /B 0
,那么这无关紧要,因为默认的 return 代码是 0
。