Batch adventures (or: expanding variables in batch files)

I was looking into writing a fairly simple batch file to install some stuff and update environment variables. At some point I wanted to do something like this (constructing a string of ‘;’ separated paths):

set env_vars = \path\to\stuff
if x%user%==xsveinbjorn (
set env_vars = %env_vars%;\another\path
)
if x%hostname%==xgefjun (
set env_vars = %env_vars%;\whoah\this\is\radical
)
echo env_vars

When I would run this I would always get

\path\to\stuff;\whoah\this\is\radical

(Notice that the second path \another\path is missing from the result) Being very new to writing batch scripts I found this extremely confusing since this sort of stuff would work like a charm in python. So I started the google machine. The reason this happens is that variables enclosed in ‘%’ are expanded when the script is read, which is quite different from the way python handles this resolving stuff at the last possible time. So when the script is read it will actually look something like this:

set env_vars = \path\to\stuff
if xsveinbjorn==xsveinbjorn (
set env_vars = \path\to\stuff;\another\path
)
if xgefjun==xgefjun (
set env_vars = \path\to\stuff;\whoah\this\is\radical
)
echo env_vars

(I resolved the variables %user% to ‘sveinbjorn’ and %hostname% to ‘gefjun’) And we can clearly see why we got the result that we got. So what we have to do is tell the batch file to expand the variables as we go along (something close to how python does things) instead of this expand-it-when-you-read-it nonsense. To do this we simply have to do three things:

  1. Add this line to the top of the code

    setlocal EnableDelayedExpansion
    
  2. Add this to the end of it

    endlocal
    
  3. Replace the enclosing ‘%’ to ‘!’ for the variable you want to delay the expansion for.

    if x%user%==xsveinbjorn (
    set env_vars = !env_vars!;\another\path
    )
    

So my original example would look like this:

setlocal EnableDelayedExpansion
set env_vars = \path\to\stuff
if xsveinbjorn==xsveinbjorn (
set env_vars = \path\to\stuff;\another\path
)
if xgefjun==xgefjun (
set env_vars = \path\to\stuff;\whoah\this\is\radical
)
echo env_vars
endlocal

Now we get the result we were looking for:

\path\to\stuff;\another\path;\whoah\this\is\radical

This also applies to loops and other places where the variable might change between the time you start the batch script and when you actually want to expand it.