Jan Tacci
Jan Tacci

Reputation: 3201

Windows Batch Function Removing Special Character From Arguments

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

Answers (2)

dbenham
dbenham

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

Magoo
Magoo

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

Related Questions