Search code examples
batch-filedos

%%F variable always referencing the last item in a FOR loop instead of the current one


This seems like is should be fairly simple, but I am having trouble getting a FOR loop in DOS to correctly report the current item it is evaluating.

I have a simple DOS batch file that loops through all files in a directory and renames them. Let's say for example my directory contains the following files:

File1.txt
File2.txt
File3.txt

I want to remove the TXT extension from each file. So my batch command looks something like:

@echo off

for %%F in ("*.txt") do (
  echo %%F
  set tmpFile=%%F
  echo %tmpFile%
  set newFile=%tmpFile:~0,-4%.xml
  echo %newFile%
)

My expected output would be:

File1.txt
File1.txt
File1.xml
File2.txt
File2.txt
File2.xml
File3.txt
File3.txt
File3.xml

Instead the output is:

File1.txt
File3.txt
File3.xml
File2.txt
File3.txt
File3.xml
File3.txt
File3.txt
File3.xml

It's as if setting %%F to a variable always uses the last file in the collection.

Am I doing something wrong? Please note I know there are better ways to simply change an extension. My finished batch file will perform many more actions, but I can't seem to get past this initial step.


Solution

  • It's because you are setting and accessing a variable within a for loop.

    You need to use delayed expansion to access them, using !'s instead of %'s.

    setlocal enabledelayedexpansion
    for %%F in ("*.txt") do (
      echo %%F
      set tmpFile=%%F
      echo !tmpFile!
      set newFile=!tmpFile:~0,-4!.xml
      echo !newFile!
    )