I have 2 Locals using delayed expansion. The 1. Local calls a subroutine which includes the 2. Local which defines 2 variables and set the values of those as the parameter values using FOR /F ...
. This works fine as long as the string do not include one or more exclamation marks. The following working script shows the issue:
@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
Output:
Inside get_substrings:
"World! wasserschutzpolizei!"
"Hello!"
Inside 1. local:
"World"
"Hello"
Expected:
Inside get_substrings:
"World! wasserschutzpolizei!"
"Hello!"
Inside 1. local:
"World! wasserschutzpolizei!"
"Hello!"
If you remove the exclamation marks in string
and substring
the script works as expected.
Because this is just an Example consider...
- Not using delayed expansion is not an option and also...
- Using one Local is undesirable.
Of course, if one or even both things are REALLY required and there is no other way I accept other answers pointing that out.
So...
- How can get the values with exclamation mark in the 1. local like i showed in the Expected part?
- Why doesn't it work with the current way of setting the param values?
Appreciate your help!
Change the return part of your :get_substrings function to:
...
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
)
But why your solution fails?
The problem is that the set "%1=%%s"
is executed in a delayed expansion context, as your complete batch uses delayed expansion.
But delayed expansion is the last expansion phase of the batch parser and it's after the parameter expansion of the %%s
.
Therefore the parser tries to expand your exclamation marks, when here is only one it will be removed, when there are two like in "World! wasserschutzpolizei!"
it expand the variable ! wasserschutzpolizei!
to it's value (in your case it seems to be empty).
The solution simply put carets in front of any exclamation mark.
But you are also using quotes in your samples it makes more things more complicated.
To avoid problems with quotes and carets it's an easy way to double all quotes, add the carets and the change the doubled quotes back to single quotes.
Is it an option for you to have delayed expansion disabled while calling the sub-routine:
@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
This would avoid to expand the for
variables %%s
and %%b
when delayed expansion is enabled, because this is the last step, so exclamation marks became consumed.