'Why does this cmd oneliner only work the second time it is called?

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?



Solution 1:[1]

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 eisn'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.

Solution 2:[2]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Christof Wollenhaupt
Solution 2 Pascal