Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Variable expansion (W2KSP2)

891 views
Skip to first unread message

Ritchie

unread,
Dec 31, 2001, 12:30:19 PM12/31/01
to
Whilst trying to obtain the value of a variable by using another variable
whose value was the name of the variable whose value I wanted obtain (still
with me?). After quite a bit of trial and error I finally got what I wanted,
but its pretty obvious I don't fully understand precisely when/how variables
are expanded.

For example, running test.bat: -

::test.bat
@echo off & set VAL=10& set Z=VAL
echo %Z%
echo %%Z%%
echo %%%Z%%%
echo %%%%Z%%%%
echo %%%%%Z%%%%%
call echo %Z%
call echo %%Z%%
call echo %%%Z%%%
call echo %%%%Z%%%%
call echo %%%%%Z%%%%%

gives the following output (only the line 'call echo %%%Z%%%' gives me what
I originally wanted): -

VAL
%Z%
%VAL%
%%Z%%
%%VAL%%
VAL
VAL
10
%Z%
%VAL%

And running the echo commands from test.bat at the command prompt gives: -

VAL
%VAL%
%%VAL%%
%%%VAL%%%
%%%%VAL%%%%
VAL
10
%10%
%%10%%
%%%10%%%

My observations and questions: -

* The only consistent result was when referencing %Z% which always gave VAL.
* The lines 'call echo %Z%' and 'call echo %%Z%%' from test.bat both give
VAL. How on earth can those two different lines be equivalent?
* A clear pattern was forming using 'echo' (without the 'call') from the
command prompt.
* The results from the 'echo' (without the 'call') in test.bat alternate
between Z and VAL (if you ignore the %'s for the moment). How is that
happening and why does it not happen when the commands are run from the
command prompt?
* Commands run from test.bat strip away the same or more pairs of %'s than
commands run the command prompt, but never less. Why is that?
* Variable expansion seems less than scientific.

Your comments/thoughts/answers will be most welcome, Ritchie.


Frank

unread,
Jan 1, 2002, 9:29:24 AM1/1/02
to
Ritchie <3c30a1dd$1...@mk-nntp-1.news.uk.worldonline.com>...

^ Whilst trying to obtain the value of a variable by using another variable
^ whose value was the name of the variable whose value I wanted obtain
(still
^ with me?).

I was hoping that someone else would tackle this but I guess they're all on
vacation.


^ @echo off & set VAL=10& set Z=VAL

^ echo %%%%%Z%%%%%

The percent sign is used to indicate a variable -- a string which is to be
replaced by another string. To use a percent sign as text it must be
escaped with a percent sign (%% is replaced with %). The command
interpreter (CMD.EXE) does as much of this that it can to the command line
before starting the new process. So your above command line gets modified
similar to this (spaces for readability):

echo %% %% %Z% %% %%
echo %% %% VAL %% %%
echo % % VAL % %
echo %%VAL%%


^ call echo %%%%%Z%%%%%

With CALL, the command line gets read and modified twice. It gets modified
as in my preceding example when first read by CMD.EXE. Then CALL sends it
back to CMD.EXE and it gets modified again:

CALL echo %% %% %Z% %% %%
CALL echo %% %% VAL %% %%
CALL echo % % VAL % %
CALL echo %%VAL%%
echo %%VAL%%
echo %VAL%

Note that the result is ideally suited for an additional invocation of CALL
to replace %VAL% with its value:

CALL CALL echo %% %% %Z% %% %%
CALL CALL echo %% %% VAL %% %%
CALL CALL echo % % VAL % %
CALL CALL echo %%VAL%%
CALL echo %%VAL%%
CALL echo %VAL%
echo 10


^ How on earth can those two different lines be equivalent?

Magic.

^ How is that happening and why does it not happen when the commands are
^ run from the command prompt?

CMD is in a different mode and does not use the same rules. I don't know
why MS does it this way.

^ * Variable expansion seems less than scientific.

That statement can be generalized to include CMD.EXE.

Frank

Ritchie

unread,
Jan 2, 2002, 7:01:40 AM1/2/02
to
"Frank" <pikfg...@aiyvzvwkvtdqrqbf.com> wrote in message
news:01c192d1$1ba56990$0125250a@aiyvzvwkvtdqrqbf...

> Ritchie <3c30a1dd$1...@mk-nntp-1.news.uk.worldonline.com>...
>
> ^ Whilst trying to obtain the value of a variable by using another
variable
> ^ whose value was the name of the variable whose value I wanted obtain
> (still
> ^ with me?).
>
> I was hoping that someone else would tackle this but I guess they're all
on
> vacation.

Its a dirty job, but someones got to do it :)

>
>
> ^ @echo off & set VAL=10& set Z=VAL
>
> ^ echo %%%%%Z%%%%%
>
> The percent sign is used to indicate a variable -- a string which is to be
> replaced by another string. To use a percent sign as text it must be
> escaped with a percent sign (%% is replaced with %). The command
> interpreter (CMD.EXE) does as much of this that it can to the command line
> before starting the new process. So your above command line gets modified
> similar to this (spaces for readability):

This was a great help to me, as I kind of overlooked occurences of '%%'
being
replaced with '%'

>
> echo %% %% %Z% %% %%
> echo %% %% VAL %% %%
> echo % % VAL % %
> echo %%VAL%%
>
>
> ^ call echo %%%%%Z%%%%%
>
> With CALL, the command line gets read and modified twice. It gets modified
> as in my preceding example when first read by CMD.EXE. Then CALL sends it
> back to CMD.EXE and it gets modified again:
>

This completed my understanding of what was going on, cheers!

> CALL echo %% %% %Z% %% %%
> CALL echo %% %% VAL %% %%
> CALL echo % % VAL % %
> CALL echo %%VAL%%
> echo %%VAL%%
> echo %VAL%
>
> Note that the result is ideally suited for an additional invocation of
CALL
> to replace %VAL% with its value:
>
> CALL CALL echo %% %% %Z% %% %%
> CALL CALL echo %% %% VAL %% %%
> CALL CALL echo % % VAL % %
> CALL CALL echo %%VAL%%
> CALL echo %%VAL%%
> CALL echo %VAL%
> echo 10
>
>
> ^ How on earth can those two different lines be equivalent?
>
> Magic.

Not anymore!!!

>
> ^ How is that happening and why does it not happen when the commands are
> ^ run from the command prompt?
>
> CMD is in a different mode and does not use the same rules. I don't know
> why MS does it this way.
>
> ^ * Variable expansion seems less than scientific.
>
> That statement can be generalized to include CMD.EXE.

And FINDSTR.EXE IMHO

>
> Frank
>

Thanks Frank. I now see how CMD.EXE goes about expanding variables and after
further experimentation, dare I say, I believe the process can be summarized
as below: -

--- Rules for commands entered at the prompt ---

* Rule 1. Working from left to right, expand variables ONLY if they have
been defined.
* Rule 2. Repeat Rule 1 for every 'call'.

Examples (for the examples, assume VAL=10 and Z=VAL)

* In the line 'echo %%Z%%', '%Z%' is expanded to VAL, the result is 'echo
%VAL%'
(if Z had not been defined the result would have been 'echo %%Z%%', ie no
change).

* In the line 'call echo %%Z%%', '%Z%' is expanded to VAL, the result is
'call echo %VAL%'
Then due to Rule 2, Rule 1 is repeated so 'call echo %VAL%' becomes 'echo
10'

--- Rules for Batch Files ---

* Rule 1.Working from left to right perform the following in order: -
a) replace '%%' with '%'
b) expand variables applying Rule 1a and Rule 1b
c) discard any leftover '%'
* Rule 2. Repeat Rule 1 for every 'call'.

Examples (for the examples, assume VAL=10 and Z=VAL)

* In the line 'echo %%Z%%', both occurences of '%%' are replaced by '%'
because of Rule 1a, the result is 'echo %Z%'

* In the line 'echo %%%Z%%%', the first '%%' is replaced by '%' because of
Rule 1a, then '%Z%' is expanded to 'VAL' because of Rule 1b, then the second
'%%' is replaced with '%' because of Rule 1a. The result is 'echo %VAL%'

* In the line 'call echo %%%Z%%%%', the first '%%' is replaced by '%'
because of Rule 1a, then '%Z%' is expanded to 'VAL' because of Rule 1b, then
the second and third '%%' is replaced with '%' because of Rule 1a. The
result is 'call echo %VAL%%'. Then because of Rule 2, Rule 1 is repeated so
the line becomes 'echo 10%'. Then because of Rule 1c, the leftover '%' is
discarded. The final result is 'echo 10'.

The rules also explain why the lines 'call echo %Z%' and 'call echo %%Z%%'
both evaluate to 'VAL' (when run from a batch file) and why the output from
the following lines alternates between 'VAL' and 'Z' (if you ignore the '%'
for a moment)

echo %Z% => VAL
echo %%Z%% => %Z%
echo %%%Z%%% => %VAL%
echo %%%%Z%%%% => %%Z%%
echo %%%%%Z%%%%% => %%VAL%%

I've worked through many examples and haven't found an exception to the
rules so far, anyone?
Can these rules be simplified further (assuming they're correct of course)?

Ritchie


Frank

unread,
Jan 2, 2002, 3:55:22 PM1/2/02
to
Ritchie <3c330...@mk-nntp-1.news.uk.worldonline.com>...

^ --- Rules for commands entered at the prompt ---

^ --- Rules for Batch Files ---

Thank you very much for your analysis. I haven't done one -- my explanation
was only from a recollection of the behavior -- and your work may save me
some in the future.

Frank

Ritchie

unread,
Jan 5, 2002, 9:23:08 AM1/5/02
to
> --- Rules for Batch Files ---
>
> * Rule 1.Working from left to right perform the following in order: -
> a) replace '%%' with '%'
> b) expand variables applying Rule 1a and Rule 1b
> c) discard any leftover '%'
> * Rule 2. Repeat Rule 1 for every 'call'.
>

Just spotted a typo in my earlier post, Rule 1b should read: -

b) expand variables applying Rule 1a and Rule 1c

Ritchie

Ritchie

unread,
Jan 6, 2002, 9:08:38 AM1/6/02
to
> --- Rules for Batch Files ---
>
> * Rule 1.Working from left to right perform the following in order: -
> a) replace '%%' with '%'
> b) expand variables applying Rule 1a and Rule 1b
> c) discard any leftover '%'
> * Rule 2. Repeat Rule 1 for every 'call'.
>

Just spotted a typo in my earlier post, Rule 1b should read: -

b) expand variables applying Rule 1a and Rule 1c

Ritchie

Ritchie

unread,
Jan 6, 2002, 3:18:49 PM1/6/02
to
> --- Rules for Batch Files ---
>
> * Rule 1.Working from left to right perform the following in order: -
> a) replace '%%' with '%'
> b) expand variables applying Rule 1a and Rule 1b
> c) discard any leftover '%'
> * Rule 2. Repeat Rule 1 for every 'call'.

Just spotted a typo in my earlier post, Rule 1b should read: -

b) expand variables applying Rule 1a and Rule 1c

Ritchie

Ritchie

unread,
Jan 6, 2002, 3:56:44 PM1/6/02
to
> --- Rules for Batch Files ---
>
> * Rule 1.Working from left to right perform the following in order: -
> a) replace '%%' with '%'
> b) expand variables applying Rule 1a and Rule 1b
> c) discard any leftover '%'
> * Rule 2. Repeat Rule 1 for every 'call'.

Just spotted a typo in my earlier post, Rule 1b should read: -

b) expand variables applying Rule 1a and Rule 1c

Ritchie

Message has been deleted
Message has been deleted
Message has been deleted

ruben...@gmail.com

unread,
May 25, 2013, 10:56:10 AM5/25/13
to
*** Please copy the following into Microsoft's Notepad for correct viewing ***

Rules for Variable Expansion

Variable expansion on a Windows Command Prompt and in a *.bat file being executed from a Windows script file are handled differently. This can be the
result of the fact that every thing in a *.bat file is considered text. (In order to quote a '%' character, another '%' character must be used (i.e. %%1, %%%1, etc.)).
Because of this, all quoting has to take priority first for clarification, then any variable expansions are handled next.
On the command line, all characters are not quoted. Therefore, meta characters are process as expected; variable expansion occurs 1st, and then the
command is process.

***********************************************************************************************************************************************************************
Note: This also applies to "single sided variables" like accessible script parameters in a *.bat file except the "single sided variable" mark is expanded/quoted on the
side where the '%' character already is (i.e. %1 with quotes becomes %%1, %%%1, %%%%1, etc.)
***********************************************************************************************************************************************************************

For example, if running the same commands from the command prompt and a batch file named test.bat, the following outpus are aquired and explained:


::test.bat
@echo off & set VAL=10& set Z=VAL


::Key point: In order to quote an '%' character in a *.bat file, you have to use another '%' character

::Command *.bat file Processing (group 1st) Output from bat file Command Line Processing (expansion 1st) Output when run From the Command Line
---------- --------------------------------- --------------------- --------------------------------------- -------------------------------------
echo %Z% Substitute variable VAL variable substitution VAL

echo %%Z%% 1st group, then print %Z% variable substitution 1st,
then there is no text expansion %VAL%

echo %%%Z%%% 1st group, expand to text
representation, substitute
variables, then
print: {%%} {%Z%} {%%} %VAL% same as above %%VAL%%

echo %%%%Z%%%% {%%} {%%} Z {%%} {%%} %%Z%% same as above %%%VAL%%%

echo %%%%%Z%%%%% {%%} {%%} {%Z%} {%%} {%%} %%VAL%% same as above %%%%VAL%%%%

********************************************************************************************************************************************************
***Remember: In a batch file, every thing is text. Therefore, quote groups are formed 1st, then variable strings are grouped together, and expanded in a
single pass. On the command line, every thing is not concidered text. This causes a single pass variable replacement only (leaving the rest
of the string data behind)
********************************************************************************************************************************************************

::Key point: the "call" command does a second pass on the text of the 1st expansion pass (like piping the 1st command into the "call" command. Unfortunatly,
the "call" command doesn't accept piped data, nor does it do any stream redirections. Therefore, this is just a work around)

::Command *.bat file Processing (group 1st) Output from bat file Command Line Processing (expansion 1st) Output when run From the Command Line
---------- --------------------------------- --------------------- --------------------------------------- -------------------------------------
call echo %Z% VAL can't be expaned any more
b/c VAL is a text string, not expansion 1st, with no other text variable
a variable string: %VAL% VAL markings, therefore ==========> VAL

call echo %%Z%% %Z% can be further expanded VAL expansion 1st to %VAL%, this text
variable is ==================> 10

call echo %%%Z%%% %VAL% can be further %%%Z%%%=>%%{%Z%}%%=>%{%VAL%}%=>
grouped, then expanded 10 %{10}% =======================> %10%

call echo %%%%Z%%%% %%Z%% can be further %%%%Z%%%%=>%%%{%Z%}%%%=>%%{%VAL%}%%
grouped, with no possible %%{10}%%
expansion %Z% ===============================> %%10%%

call echo %%%%%Z%%%%% %%VAL%% can be further %%%%%Z%%%%%=>%%%%{%Z%}%%%%=>
grouped with no possible %%%{%VAL%}%%%=>%%%{10}%%%
expansion %VAL% ===============================> %%%10%%%

***************************************************************************************************************************
***Remember: Each additional use of the "call" command causes another variable expansion and evaluation process if possible
***************************************************************************************************************************

jeb

unread,
Jun 6, 2013, 3:58:00 AM6/6/13
to
[09:56:51.705] Am Samstag, 25. Mai 2013 16:56:10 UTC+2 schrieb ruben...@gmail.com:
> Rules for Variable Expansion
>
> Variable expansion on a Windows Command Prompt and in a *.bat file
> being executed from a Windows script file are handled differently.
> This can be the result of the fact that every thing in a *.bat file
> is considered text.
> (In order to quote a '%' character, another '%' character must be used (i.e. %%1, %%%1, etc.)).
>
> Because of this, all quoting has to take priority first for clarification,
> then any variable expansions are handled next.

Hi Ruben,

I have to criticize some points.

As I understand you use it in the context of escaping a character like % is escaping by another %. Or a & can be escaped with a caret ^&.
The word "quote" is normally used for the quote " character, to say something is quoted means it stands in quotes like "Dog & cat".

Only the escaping of a percent sign is "before" the variable expansion, or better it's done in the same parser phase.
All other escapings/quotings are done after the percent expansion phase.

set "var1=cat and dog"
set "var2=cat & dog"
echo #1a %var1%
echo #1b %var1:and=^&%
echo #2a %var2%
echo #2b %var2:&=and%

Output:
#1a cat and dog
#1b cat & dog
#2a cat ... Failure .... The command "dog" can't be found
#2b cat and dog

With a call it's not directly possible to escape any special character.
All of the following fails
call echo cat & dog
call echo cat ^& dog
call echo cat ^^& dog
call echo cat ^^^& dog
call echo cat ^^^^& dog

But this works
set "var2=cat ^& dog"
call echo %%var2%%

The cause is, that all carets are doubled by a call first, and later they are reduced by the parser again (if they are not quoted!).

call echo #1 ^^^^
call call echo #2 ^^^^
call call call echo #3 ^^^^

call echo #4 "^^^^"
call call echo #5 "^^^^"
call call call echo #6 "^^^^"
Output:
#1 ^^
#2 ^^
#3 ^^
#4 "^^^^^^^^"
#5 "^^^^^^^^^^^^^^^^"
#6 "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"

jeb
0 new messages