Consider the following code executed on a Windows (10) cmd (this is actually a simplyfied version of a script that shows an erronous behavior):
type nul >> "a"
set "e=" & for /f "delims=" %F in ('dir /b a') do (set "e=%F" & if not defined e (echo "") else (echo "%e%"))
In short: reset the variable e
, loop over files found by dir
, make e
the current filename, if e
is defined, print it.
Run for the first time, it produces the output %e%
. When executed a second time in the same shell, it produces a
(which is what I would have expected). This doesn't happen when there is no for
involved.
What causes this behavior and how do I always get the correct output?
CodePudding user response:
When CMD.EXE executes a line, it first replaces all variables with the current value for the entire command line. Then it executes the line. Because e
isn't defined when the second command is executed, CMD doesn't remove %e%
. The second time, the environment variable exists and gets replaced.
%e%
is not a variable like in other languages that gets evaluated at the time the interpreter gets to the command.
If you change you sample script to
type nul >> "a"
set e=b
set "e=" & for /f "delims=" %F in ('dir /b a') do (set "e=%F" & if not defined e (echo "") else (echo "%e%"))
the output is b
rather than %e%
or a
because that is the value of e
at the time the line is executed.
CodePudding user response:
The reason for this seems to be the immediate expansion of variables by the cmd
. See this post for a nicer description. According to the cmd description (MSDN), cmd
contains a flag /v:on
that allows delayed variable expansion. Above example then needs to become:
type nul >> "a"
set "e=" & for /f "delims=" %F in ('dir /b a') do (set "e=%F" & if not defined e (echo "") else (echo "!e!"))
This behavior is unexpected at least. The cmd
is such a poor environment that it hurts me everytime I have to look at it.