Empty variables during FOR loops in batch files

Batch files (*.bat / *.cmd) are easy to build and yet powerful scripts .
Although time is catching up and batch files are more and more replaced by vbScript and PowerShell, there are occasions you need them.

Batch files are especially powerful when you’re using (for) loops and variables. But the combination of those two is somewhat of a problem. Why? It doesn’t (seem to) work…

Let’s take the following situation.
You want to build a script that searches for files with a given extension in a given directory. You then strip the extension of the filename and process the file. This script would look like this:

@ECHO OFF
REM Set constants
REM -------------
SET strSourceDirectory=C:App-V
SET strWildcard=*.osd

REM Search for files
REM —————-
FOR /F “tokens=* delims=” %%A IN (‘DIR /B /S %strSourceDirectory%%strWildcard%’) DO (

REM Determine filename
REM ——————
SET strFileName=%%A

REM Determine filename without extension
REM ————————————
SET strFileNameWithoutExtension=%strFilename:~0,-4%
ECHO Filename = %strFileNameWithoutExtension%
)

You would expect a list of files without the extension (.osd is 4 characters). However, the outcome of the script looks like this:

Filename =
Filename =
Filename =
Filename =

There is no result, no outcome. Not what you would expect.

The reason for this lies in the way a batch file processes variables (or expands the variables). This doesn’t happen during command execution, but before execution. Of course you can solve this issue. By enabling delayed variable expansion and reading the variables the right way.

First of all you need to enable delayed variable expansion. This can be achieved by calling the command interpreter via the command CMD /V:ON /C or simply by adding SETLOCAL ENABLEDELAYEDEXPANSION in the batch file.

Next you need to read the variables on a different way. Not with percent signs, like you’re used to, but with exclamation marks.

Let take a look at the same script, but this time with delayed variables expansion.

@ECHO OFF
REM Enable delay expansion
REM ----------------------
SETLOCAL ENABLEDELAYEDEXPANSION

REM Set constants
REM ————-
SET strSourceDirectory=C:App-V
SET strWildcard=*.osd

REM Search for files
REM —————–
FOR /F “tokens=* delims=” %%A IN (‘DIR /B /S %strSourceDirectory%%strWildcard%’) DO (

REM Determine filename
REM ——————
SET strFileName=%%A

REM Determine filename without extension
REM ————————————
SET strFileNameWithoutExtension=!strFilename:~0,-4!
ECHO Filename : !strFileNameWithoutExtension!
)

Now if we execute the batch file, this would be the result. As expected.

Filename = C:App-VGlobalSoftGrid ClientOSD Cacheffd89791-cecb-4550-a3b3-3d9805961e13
Filename = C:App-VGlobalSoftGrid ClientOSD Cacheffd89791-cecb-4550-a3b3-3d9805961e13
Filename = C:App-VGlobalSoftGrid ClientOSD Cacheffd89791-cecb-4550-a3b3-3d9805961e13
Filename = C:App-VGlobalSoftGrid ClientOSD Cacheffd89791-cecb-4550-a3b3-3d9805961e13

 

Ingmar Verheij