How do I call a subroutine with a parameter being a variable containing an ampersand (&)?
There is no error, but the call never seems to execute.
example.bat
@echo off
setlocal enableDelayedExpansion
rem Doesn't work
set val=with^&ersand
call :Output !val!
rem Works fine
set val=without_ampersand
call :Output !val!
goto End
:Output
set "line=%1"
echo Called: !line!
goto :eof
End:
Output:
Called: without_ampersand
Edit:
The usage of delayedExpansion is not required. It was just used in this example. A way to do it without using delayedExpansion is preferred.
The question is focusing on "How do I call" rather than "How do I initially set the variable". The variable may come from user input or a for /f
loop (as is my case).
Best Answer
The batch escape rules are quite nasty, but the behavior is totally predictable if you know the rules.
The info you need to understand the problem is available at How does the Windows Command Interpreter (CMD.EXE) parse scripts? in phases 1, 2, 5, and 6 of the accepted answer. But good luck absorbing that info any time soon :-)
There are two fundamental design issues that lead to your problem: - Phase 6 doubles all carets, which then restarts phase 2 (actually phases 1, 1.5 and 2). - But phase 2 requires
&
to be escaped as^&
. Note it must be a single^
, not doubled!The only way to get your approach to work is to introduce the
^
after the phase 6 caret doubling has occurred.ESC is defined to hold
^
.The first round of phase 1 expands
%%ESC%%
to%ESC%
the second round of phase 1 (initiated by phase 6) expands
%ESC%
to^
This is all totally impractical, especially if you don't know what the content is going to be.
The only sensible strategy to reliably pass any value into a CALLed routine is to pass by reference. Pass the name of a variable that contains the string value, and expand that value within your subroutine using delayed expansion.