Batch: Unexpected Variable Results in Subroutine
An answer to a previous question suggests this FOR line. Now I am trying to use the variable. My batch script at present:
@echo off
cls
for %%G in ("3D Objects","Documents","Downloads","Music","Pictures","Videos") do call :sub1 %%G
:sub1
echo %%G
set apath=%%~G
echo %apath%
goto :eof
:End
The output from this script is seven iterations of this:
%G
%~G
The subroutine seems to be doing something to the variable. Because when I substitute these lines:
for %%G in ("3D Objects","Documents","Downloads","Music","Pictures","Videos") do (
echo %%G
set apath=%%~G
echo %apath%
)
I get the desired result: six pairs of output of this nature:
"3D Objects"
3D Objects
where the tilde removes the quotation marks, as expected.
In the first code sample, the production of seven (not six) pairs of output lines suggests that the subroutine may be disregarding the quotation marks, rendering "3D" and "Objects" as two separate items -- which was an issue addressed in the previous question.
I starting tinkering with the subroutine approach because I was having problems achieving a certain outcome using the simpler approach presented in the second code sample (above). Possibly delayed expansion would fix that, but at the cost of additional complexity. Not to deny that the subroutine's "goto :eof" line is also a little confusing, even if it does work.
My specific question is, what's going wrong with the variable, when used in the subroutine? But if there is a better way, I would also appreciate at least a link in that direction.
Solution 1:
You are passing the value of the for loop iteration to a subroutine using call so you want to enclose that (passed variable placeholder) with a double quote and then reference the passed in variable within that subroutine as %1
or %~1
to strip out the enclosing double quotes.
Using the GOTO :EOF
at the end of each called subroutine will pass control back to the original caller subroutine so it can continue to process the rest
its logic if applicable after the call
command.
@echo off
cls
for %%G in ("3D Objects","Documents","Downloads","Music","Pictures","Videos") do call :sub1 "%%~G"
goto :eof
:sub1
echo %1
set apath=%~1
echo %apath%
goto :eof
:End
Output
"3D Objects"
3D Objects
"Documents"
Documents
"Downloads"
Downloads
"Music"
Music
"Pictures"
Pictures
"Videos"
Videos
Supporting Resources
- FOR
-
Command Line arguments (Parameters)
Arguments can also be passed to a subroutine with
CALL:
CALL :my_sub 2468
You can get the value of any argument using a % followed by it's numerical position on the command line. The first item passed is always %1 the second item is always
%2
and so on%*
in a batch script refers to all the arguments (e.g.%1 %2 %3 %4 %5
...%255
) only arguments%1
to%9
can be referenced by number. -
CALL
Passing by Reference
In addition to passing numeric or string values on the command line, it is also possible to pass a variable name and then use the variable to transfer data between scripts or subroutines. Passing by reference is a slightly more advanced technique but can be particularly useful when the string contains characters that are CMD delimiters or quotes.
CALL a subroutine (:label)
The
CALL
command will pass control to the statement after the label specified along with any specified parameters. To exit the subroutine specifyGOTO :eof
this will transfer control to the end of the current subroutine. -
CALL /?
CALL command now accepts labels as the target of the CALL. The syntax is: CALL :label arguments In addition, expansion of batch script argument references (%0, %1, etc.) have been changed as follows: %* in a batch script refers to all the arguments (e.g. %1 %2 %3 %4 %5 ...) Substitution of batch parameters (%n) has been enhanced. You can now use the following optional syntax: %~1 - expands %1 removing any surrounding quotes (")