How can I echo the string %I
in a secure way, independent on whether or not the echo
command line is placed within a for %I
loop?
For example, in command prompt (cmd
):
>>> rem // `echo` is outside of `for` scope, so this works:
>>> echo %I
%I
>>> rem // `echo` is inside of `for` scope, so `%I` is resolved:
>>> for %I in (.) do @echo %I
.
>>> rem // escaping does not help, `%I` is still resolved:
>>> for %I in (.) do @(echo ^%I & echo %^I & echo ^%^I & echo %%I)
.
.
.
%.
And in a batch file...:
@echo off & rem // Here you need to double the `%` signs!
rem // `echo` is outside of `for` scope, so this works:
echo %%I & echo %%%%I
echo/
rem // `echo` is inside of `for` scope, so `%%I` is resolved:
for %%I in (.) do (echo %%I & echo %%%%I)
echo/
rem // escaping does not help, `%%I` is still resolved:
for %%I in (.) do (echo ^%%I & echo %%^I & echo ^%%^I & echo ^%^%I & echo ^%^%^I & echo ^%%^%%^I)
...the result is:
%I
%%I
.
%.
.
.
.
I
^I
%.
So how do I have to change the above approaches (both cmd
and batch file) to get %I
echoed?
There are two ways to work around the unintended expansion of the for
reference %I
:
Delayed Expansion
In cmd
:
>>> rem // Ensure that delayed expansion is enabled!
>>> set "STR=%I"
>>> echo !STR!
%I
>>> for %I in (.) do @echo !STR!
%I
In a batch file...:
@echo off & rem // Here you need to double the `%` signs!
setlocal EnableDelayedExpansion
set "STR=%%I"
echo !STR!
for %%I in (.) do echo !STR!
set "STR=%%%%I"
echo !STR!
for %%I in (.) do echo !STR!
endlocal
...with the result:
%I
%I
%%I
%%I
However, delayed expansion could harm under certain circumstances; so could the environment localisation done by setlocal
/endlocal
.
But there is still another way:
Wrap Around Another for
Loop
In cmd
:
>>> for %J in (%I) do @echo %J
%I
>>> for %J in (%I) do @for %I in (.) do @echo %J
%I
In a batch-file...:
@echo off & rem // Here you need to double the `%` signs!
for %%J in (%%I) do (
echo %%J
for %%I in (.) do echo %%J
)
for %%J in (%%%%I) do (
echo %%J
for %%I in (.) do echo %%J
)
...with the result:
%I
%I
%%I
%%I
Although you cannot echo %%J
now any more, of course.
Wrap Around Another for
Loop (edited according to dbenham's suggestion)
In cmd
:
>>> for %J in (%) do @echo %JI
%I
>>> for %J in (%) do @for %I in (.) do @echo %JI
%I
In a batch-file...:
@echo off & rem // Here you need to double the `%` signs!
for %%J in (%%) do (
echo %%JI
for %%I in (.) do echo %%JI
)
for %%J in (%%%%) do (
echo %%JI
for %%I in (.) do echo %%JI
)
...with the result:
%I
%I
%%I
%%I
This time even %%J
could be echoed.