We will start with a simple case.
set "var=" set "var=test" echo %var%
Reading the code, it deletes the contents of the variable, assigns it a new value and echoes it.
Let me slightly change this combination of the last two commands
set "var=" set "var=test" & echo %var%
The "same" code, but in this case the output to the console does not display the value in the variable.
Why? In batch files, lines for execution are parsed and then executed. During the analysis phase, each read operation of the variables (where you retrieve the value of the variable) is replaced by the value stored inside the variable during parsing. Once this is done, the resulting command will be executed. Thus, in the previous example, when the second line is parsed, it is converted to
set "var=test" & echo
now there are no read operations in the line and no value for the echo, since when reading the line the variable did not matter (it will be assigned when the line is executed), so the read operation was replaced with nothing. At this point, the code is executed, and the perceived behavior is that the set command failed because we did not get the โobviousโ value selected for the console.
This behavior also occurs in blocks. A block is a set of lines enclosed in parentheses (usually for and if ) and is processed by the parser, as if all lines in the block were only one line with concatenated commands. A complete block is read, all variable reading operations are deleted and replaced with a value inside the variables, and then a complete block is executed without reference to the variables inside.
At run time, there is no read operation for variables inside the block, only its initial values, so any value assigned to a variable inside the block cannot be extracted inside the same block, since there is no read operation.
So in this code
set "test=before" if defined test ( set "test=after" echo %test% )
after the first set executed, the block ( if command and all the code enclosed in its bracket) will be analyzed and converted to
if defined test ( set "test=after" echo before )
shows the "wrong" value.
The usual way to handle this is to use a delayed extension. This will allow you to change, where necessary, the syntax for reading a variable from %var% to !var! , indicating to the parser that the read operation should not be deleted during parsing, but is delayed until the command is executed.
setlocal enabledelayedexpansion set "var=" set "var=test" & echo !var!
Now the third line is converted during parsing to
set "var=test" & echo !var!
yes, the reference to the variable is not deleted. The read operation is delayed until the echo command is executed when the variable value has been changed.
So
%var% is a variable reference that will be replaced during parsing
!var! is a reference to a variable that will be replaced at runtime
%x with x one character is usually for replaceable parameter, a variable that will contain the current element that will interact. By nature, it will be expanded at runtime. One percent sign syntax is used on the command line. Inside batch files, the percent sign must be escaped, and the syntax for referencing removable parameters is: %%x