批处理 - Set/Reset 参数调用带有感叹号 (!) 和延迟扩展的子程序?
Batch - Set/Reset parameters calling subroutine with exclamation mark (!) and delayed expansion?
我有 2 个 Locals 使用延迟扩展。 1. Local 调用一个包含 2. Local 的子程序,该子程序定义了 2 个变量并使用 FOR /F ...
将这些变量的值设置为参数值。只要字符串不包含一个或多个感叹号,这就可以正常工作。以下工作脚本显示了该问题:
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
CALL :get_substrings testString substr
ECHO Inside 1. local:
ECHO !testString!
ECHO !substr!
EXIT /B 0
ENDLOCAL
:get_substrings
SETLOCAL ENABLEDELAYEDEXPANSION
SET string="World^! wasserschutzpolizei^!"
SET substring="Hello^!"
ECHO Inside get_substrings:
ECHO !string!
ECHO !substring!
FOR /F "delims=" %%s IN ("!string!") DO FOR /F "delims=" %%b IN ("!substring!") DO (
ENDLOCAL & SET "%1=%%s" & SET "%2=%%b" & EXIT /B 0
)
EXIT /B 0
输出:
Inside get_substrings:
"World! wasserschutzpolizei!"
"Hello!"
Inside 1. local:
"World"
"Hello"
预计:
Inside get_substrings:
"World! wasserschutzpolizei!"
"Hello!"
Inside 1. local:
"World! wasserschutzpolizei!"
"Hello!"
如果删除 string
和 substring
中的感叹号,脚本将按预期运行。
因为这只是一个示例,请考虑...
- 不使用延迟扩展不是一种选择,而且...
- 使用一个 Local 是不可取的。
当然,如果确实需要其中一项或两项,并且没有其他方式,我会接受其他指出这一点的答案。
所以...
- 如何获取 1.local 中带有感叹号的值,就像我在 Expected 部分中显示的那样?
- 为什么它不适用于当前设置参数值的方式?
感谢您的帮助!
将 :get_substrings 函数的 return 部分更改为:
...
set "return1=!string:"=""!"
set "return1=%return1:!=^^^!%"
set "return1=!return1:""="!"
set "return2=!substring:"=""!"
set "return2=%return2:!=^^^!%"
set "return2=!return2:""="!"
FOR /F "delims=" %%s IN ("!return1!") DO FOR /F "delims=" %%b IN ("!return2!") DO (
ENDLOCAL & SET "%1=%%s" & SET "%2=%%b" & EXIT /B 0
)
但是为什么你的解决方案失败了?
问题是 set "%1=%%s"
是在延迟扩展上下文中执行的,因为您的整个批处理使用延迟扩展。
但是延迟扩展是批解析器的最后一个扩展阶段,它是在 %%s
.
的参数扩展之后
因此解析器会尝试扩展你的感叹号,当这里只有一个时它将被删除,当有两个像 "World! wasserschutzpolizei!"
它扩展变量 ! wasserschutzpolizei!
到它的值(在你的情况下它似乎为空)。
该解决方案只是将插入符号放在感叹号前面。
但是你也在你的样本中使用引号,这让更多的事情变得更复杂。
为避免引号和插入符号出现问题,这是将所有引号加倍、添加插入符号并将双引号改回单引号的简单方法。
是否可以选择在调用子例程时禁用延迟扩展:
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
CALL :get_substrings testString substr
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO Inside 1. local:
ECHO !testString!
ECHO !substr!
ENDLOCAL
EXIT /B 0
ENDLOCAL
:get_substrings
SETLOCAL ENABLEDELAYEDEXPANSION
SET string="World^! wasserschutzpolizei^!"
SET substring="Hello^!"
ECHO Inside get_substrings:
ECHO !string!
ECHO !substring!
FOR /F "delims=" %%s IN ("!string!") DO FOR /F "delims=" %%b IN ("!substring!") DO (
ENDLOCAL & SET "%1=%%s" & SET "%2=%%b" & EXIT /B 0
)
EXIT /B 0
这将避免在启用延迟扩展时扩展for
变量%%s
和%%b
,因为这是最后一步,所以感叹号被消耗了。
我有 2 个 Locals 使用延迟扩展。 1. Local 调用一个包含 2. Local 的子程序,该子程序定义了 2 个变量并使用 FOR /F ...
将这些变量的值设置为参数值。只要字符串不包含一个或多个感叹号,这就可以正常工作。以下工作脚本显示了该问题:
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
CALL :get_substrings testString substr
ECHO Inside 1. local:
ECHO !testString!
ECHO !substr!
EXIT /B 0
ENDLOCAL
:get_substrings
SETLOCAL ENABLEDELAYEDEXPANSION
SET string="World^! wasserschutzpolizei^!"
SET substring="Hello^!"
ECHO Inside get_substrings:
ECHO !string!
ECHO !substring!
FOR /F "delims=" %%s IN ("!string!") DO FOR /F "delims=" %%b IN ("!substring!") DO (
ENDLOCAL & SET "%1=%%s" & SET "%2=%%b" & EXIT /B 0
)
EXIT /B 0
输出:
Inside get_substrings:
"World! wasserschutzpolizei!"
"Hello!"
Inside 1. local:
"World"
"Hello"
预计:
Inside get_substrings:
"World! wasserschutzpolizei!"
"Hello!"
Inside 1. local:
"World! wasserschutzpolizei!"
"Hello!"
如果删除 string
和 substring
中的感叹号,脚本将按预期运行。
因为这只是一个示例,请考虑...
- 不使用延迟扩展不是一种选择,而且...
- 使用一个 Local 是不可取的。
当然,如果确实需要其中一项或两项,并且没有其他方式,我会接受其他指出这一点的答案。
所以...
- 如何获取 1.local 中带有感叹号的值,就像我在 Expected 部分中显示的那样?
- 为什么它不适用于当前设置参数值的方式?
感谢您的帮助!
将 :get_substrings 函数的 return 部分更改为:
...
set "return1=!string:"=""!"
set "return1=%return1:!=^^^!%"
set "return1=!return1:""="!"
set "return2=!substring:"=""!"
set "return2=%return2:!=^^^!%"
set "return2=!return2:""="!"
FOR /F "delims=" %%s IN ("!return1!") DO FOR /F "delims=" %%b IN ("!return2!") DO (
ENDLOCAL & SET "%1=%%s" & SET "%2=%%b" & EXIT /B 0
)
但是为什么你的解决方案失败了?
问题是 set "%1=%%s"
是在延迟扩展上下文中执行的,因为您的整个批处理使用延迟扩展。
但是延迟扩展是批解析器的最后一个扩展阶段,它是在 %%s
.
的参数扩展之后
因此解析器会尝试扩展你的感叹号,当这里只有一个时它将被删除,当有两个像 "World! wasserschutzpolizei!"
它扩展变量 ! wasserschutzpolizei!
到它的值(在你的情况下它似乎为空)。
该解决方案只是将插入符号放在感叹号前面。
但是你也在你的样本中使用引号,这让更多的事情变得更复杂。
为避免引号和插入符号出现问题,这是将所有引号加倍、添加插入符号并将双引号改回单引号的简单方法。
是否可以选择在调用子例程时禁用延迟扩展:
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
CALL :get_substrings testString substr
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO Inside 1. local:
ECHO !testString!
ECHO !substr!
ENDLOCAL
EXIT /B 0
ENDLOCAL
:get_substrings
SETLOCAL ENABLEDELAYEDEXPANSION
SET string="World^! wasserschutzpolizei^!"
SET substring="Hello^!"
ECHO Inside get_substrings:
ECHO !string!
ECHO !substring!
FOR /F "delims=" %%s IN ("!string!") DO FOR /F "delims=" %%b IN ("!substring!") DO (
ENDLOCAL & SET "%1=%%s" & SET "%2=%%b" & EXIT /B 0
)
EXIT /B 0
这将避免在启用延迟扩展时扩展for
变量%%s
和%%b
,因为这是最后一步,所以感叹号被消耗了。