The Problem
In a main batch file, values are pulled from a .txt file (and SET
as values of variables within this batch file). These values may each contain %
characters.
These are read from the .txt file with no issues. However, when a variable with a value containing a %
character is passed to a second batch file, the second batch file interprets any %
characters as a variable expansion. (Note: There is no control over the second batch file.)
Example
echo %PERCENTVARIABLE%
Output: I%LOVE%PERCENT%CHARACTERS%
When passed to a second file and then echo'ed, would (probably) become IPERCENT
, as it interprets %LOVE%
and %CHARACTERS%
as unset variables.
Research
I found the syntax to find and replace elements within a string in a batch file, as I thought I could potentially replace a %
character with %%
in order to escape it. However I cannot get it to work.
The syntax is -
set string=This is my string to work with.
set string=%string:work=play%
echo %string%
Where the output would then be This is my string to play with.
.
Questions
%
characters using the find and replace syntax
in a variable? (If not, is there another way?)There are no simple rules that can be applied in all situations.
There are a few issues that make working with string literals in parameters difficult:
&
, |
, etc. must be escaped or quoted. Escaping is difficult because it can be confusing as to how many times to escape. So the recommendation is to usually quote the string.<space>
, <tab>
, =
, ;
and ,
cannot be included in a parameter value unless it is quoted.%
characters, and there is no way to prevent this. Executing a script without CALL will not double the %
characters. But if a script calls another script and expects control to be returned, then CALL must be used.So we have a catch-22: On the one hand, we want to quote parameters to protect against poison characters and spaces (token delimiters). But to protect percents we don't want to quote.
The only reliable method to reliably pass string literals without concern of value corruption is to pass them by reference via environment variables.
!%1!
. Delayed expansion must be enabled before that syntax can be used - simply issue setlocal enableDelayedExpansion
.The beauty of delayed expansion is you never have to worry about corruption of poison characters, spaces, or percents when the variable is expanded.
Here is an example that shows how the following string literal can be passed to a subroutine"<%|,;^> This & that!" & the other thing! <%|,;^>
@echo off
setlocal enableDelayedExpansion
set "parm1="^<%%^|,;^^^^^> This ^& that^^!" & the other thing^! <%%|,;^^^>"
echo The value before CALL is !parm1!
call :test parm1
exit /b
:test
echo The value after CALL is !%1!
-- OUTPUT --
The value before CALL is "<%|,;^> This & that!" & the other thing! <%|,;^>
The value after CALL is "<%|,;^> This & that!" & the other thing! <%|,;^>
But you state that you have no control over the 2nd called script. So the above elegant solution won't work for you.
If you were to show the code of the 2nd script, and show exactly what value you were trying to pass, then I might be able to give a solution that would work in that isolated situation. But there are some values that simply cannot be passed unless delayed expansion is used with variable names. (Actually, another option is to put the value in a file and read the value from the file, but that also requires change to your 2nd script)
may be...?
input.txt
I%LOVE%PERCENT%CHARACTERS%
batch1.bat
@echo off
setlocal enableDelayedExpansion
set/P var=<input.txt
echo(In batch 1 var content: %var%
set "var=!var:%%=%%%%!"
call batch2.bat "%var%"
endlocal
exit/B
batch2.bat
@echo off
set "var=%~1"
echo(In batch 2 var content: %var%
exit/B
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With