Reputation: 3201
I am creating a Windows batch file with a function that takes a variable number of arguments. When I call this batch file the string that I am passing to it contains the special character %.
Prior to calling this function I set a variable containing the string (which contains the special character) and call the function as follows:
SETLOCAL ENABLEDELAYEDEXPANSION
...
SET "MYSTRING=Hello "%%V""
ECHO My String=!MYSTRING!
CALL :BATCH_FUNCTION !MYSTRING!
GOTO :EOF
Here is my batch function definition:
:BATCH_FUNCTION
SET "ARGS=%*"
ECHO Arguments=!ARGS!
GOTO :EOF
The problem I am running into is the % sign is getting stripped out inside the function.
Here are the outputs to demonstrate:
My String=Hello "%V"
Arguments=Hello "V"
Can anyone tell me how to setup either the function arguments or the function itself to not strip off the % sign?
Thank you.
Upvotes: 2
Views: 1991
Reputation: 130809
The problem is that CALL has an extra round of parsing that consumes the %
. See phase 6 in How does the Windows Command Interpreter (CMD.EXE) parse scripts? for more information.
One solution that requires minimal change to your code is to use variable expansion search and replace to double up the percents in your CALL statement. The delayed expansion search and replace occurs in phase 5, and then phase 6 consumes the extra percent to get back to the original value. Note that the percents must be doubled in the search and replace expression because phase 1 percent consumption occurs before the delayed expansion in phase 5.
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET "MYSTRING=Hello "%%V""
ECHO My String=!MYSTRING!
CALL :BATCH_FUNCTION !MYSTRING:%%=%%%%!
GOTO :EOF
:BATCH_FUNCTION
SET "ARGS=%*"
ECHO Arguments=!ARGS!
GOTO :EOF
But that is not the best way to pass string values to functions. There are other characters that cause additional complications. And there is no good solution for passing a quoted ^
literal in a CALL statement.
The best way to pass any string value to a function is to pass by reference, meaning pass the name of a variable, and then use delayed expansion to access the value of the variable. However, this does not help with the %*
construct.
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET "MYSTRING=Hello "%%V""
ECHO My String=!MYSTRING!
CALL :BATCH_FUNCTION MYSTRING
GOTO :EOF
:BATCH_FUNCTION
SET "ARG1=!%1!"
ECHO ARG1=!ARG1!
GOTO :EOF
Upvotes: 2
Reputation: 79982
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "MYSTRING=Hello "%%V""
ECHO My String=!MYSTRING!
CALL :BATCH_FUNCTION !MYSTRING:%%=%%%%!
CALL :BATCH_FUNCTION2 MYSTRING
GOTO :EOF
:BATCH_FUNCTION
SET "ARGS=%*"
ECHO Arguments=!ARGS!
GOTO :EOF
:BATCH_FUNCTION2
FOR /f "tokens=1*delims==" %%a IN ('set %1') DO IF /i "%1"=="%%a" ECHO Arguments=%%b
GOTO :EOF
Here's two different ways. Neither is bullet-proof. Oftentimes, a batch solution processing strings has holes.
Upvotes: 1