# Delayed Expansion is Enabled but Variables are not expanding in FOR loop



## ttx336 (Nov 7, 2012)

```
@echo off
SetLocal EnableDelayedExpansion

SET count=1 

FOR /f "tokens=*" %%G IN ('dir /b') DO (
	echo %count%:%%G
	set /a count+=1
	)
	
EndLocal
```
Just a simple example, but the variable stays at 1


```
@echo off
setlocal EnableDelayedExpansion 
:: count to 5 storing the results in a variable
set _tst=0
FOR /l %%G in (1,1,5) Do (echo [!_tst!] & set /a _tst+=1)
echo Total = !_tst!
```
This one works... why not the first one? I would much rather use the first method in a much larger script that I am working on...

Thx in advance, GB


----------



## Squashman (Apr 4, 2003)

Well in your first batch file you are using % symbols to reference your variable expansion. In your 2nd batch file you are using ! symbol to reference your variable expansion. Delayed Expansion requires you to use the ! exclamation.


----------



## ttx336 (Nov 7, 2012)

I sure am confused about when to use ! and when to use %, hopefully, I will get a better understanding of this. In previous attempts at this, when I have used the wrong one I got no output at all, but that could be due to the fact that, as I think about it, in this case, I had declared and loaded the variable with a 1.

One thing I noticed in the working model, the first output of !count! puts out, of course, 1 but also what looks like two spaces, could be just one space, but subsequent output has no spaces, only 2:file.txt etc.

Thanks for your help.

-Gary


----------



## foxidrive (Oct 20, 2012)

Your second snippet works here.

!variable! can be used anywhere after a 'setlocal enabledelayedexpansion' is declared (and before an 'endlocal' if one of those is used).

%variable% can also be used - but only when it is already set before being used inside a loop with parentheses.

If you have random spaces then watch for trailing spaces when you set variables.


----------



## ttx336 (Nov 7, 2012)

foxidrive said:


> Your second snippet works here.
> 
> !variable! can be used anywhere after a 'setlocal enabledelayedexpansion' is declared (and before an 'endlocal' if one of those is used).
> 
> ...


Geez, I often say this, and I truly mean it in this case, there are some smart people out there... and you and Squashman are two of them. There was a trailing space and of course, eliminating it fixed the issue. Just for interest, I also tried adding the /a for math, with the trailing space intact and that also resolved the issue.


```
@Echo off
SetLocal EnableExtensions EnableDelayedExpansion
SetLocal EnableDelayedExpansion
cls

set indate=%1
set /a count=0

for /f "skip=4 tokens=1-7 delims=/ " %%i in ('dir /tw /a-d') do (
	
set /a count+=1

:Month	
	set _month=%%i
	set /a _month=100!_month! %% 100
	set /a _month=!_month! * 100

:Day	
	set _day=%%j
	set /a _day=100!_day! %% 100

:Year
	set _year=%%k
	set /a _year=!_year! * 10000

:Combined	
	set /a _fdate=!_year! + !_month! + !_day!
	
	if !indate! LSS !_fdate! (
		echo !count!: %%o is newer than !indate!
				)
	)
```
In this code, where I initialized *indate*, I had to use only one percent sign, but for the tokens, I had to use two... why is that? And why is it we must use %variable% or !variable!? Is that simply how the parser differentiates between variables, tokens and command parameters? Is my terminology even correct?

and btw, will you please ctitique my code and point out where I might have done better? The command line is just the command filename (of course) and a date in the YYYYMMDD format, ie *C:\newer.cmd 20100809*

The purpose of the code is to find and list files that are newer than the supplied date.
-GB


----------



## Squashman (Apr 4, 2003)

Then use the FORFILES command.


----------



## foxidrive (Oct 20, 2012)

Another method is to use the %%~ta date/time variable but this is specific to Windows region settings.

The line that generates the date expects DD/MM/YYYY in the date format in this case. Remove the REM to see what format yours is in.


```
@echo off
SetLocal EnableDelayedExpansion
cls
set indate=%1

for /f "delims=" %%a in ('dir /b /tw /a-d') do (
rem echo "%%a" - "%%~ta"
set d=%%~ta
set d=%d:6,4%%d:0,2%%d:3,2%
if %indate% LSS !d! echo %%a is newer than %indate%
)
pause
```
You can also use Xcopy with the /D switch and supply a date - and using the /L switch makes it just list the filenames. That also takes the timestamp into account and is a more robust/simple way of comparing date/time.

In a forINdo command it uses two %% for the metavariables in batch files, but only one % from a command prompt.

A replaceable parameter from the command line only uses %1 %2 %3 etc and an environment variable is always designated by surrounding it with % or ! for delayed expansion.

There are other ways to solve this issue and the one you use is personal preference a lot of the time - but it's often useful to adapt techniques that don't rely on regional settings - if possible, sometimes it's not. Batch files can be kludgy that way.


----------



## ttx336 (Nov 7, 2012)

```
@echo off
SetLocal EnableDelayedExpansion
cls
set indate=%1

for /f "delims=" %%a in ('dir /b /tw /a-d') do (
set d=%%~ta
set d=!d:~6,4!!d:~0,2!!d:~3,2!
if %indate% LSS !d! echo %%a is newer than %indate%
)
```
This is what I had to do in order to get it to run... I had to add the ~ tilde and change from the % to the !

from this:
set d=%d:6,4%%d:0,2%%d:3,2%

to this:
set d=!d:~6,4!!d:~0,2!!d:~3,2!


----------



## foxidrive (Oct 20, 2012)

Well done.


----------



## ttx336 (Nov 7, 2012)

I am amazed at how much you tightened up that code! I am so very glad that I asked you to take a look at it.

Thank you so very much,
-Gary


----------



## ttx336 (Nov 7, 2012)

Squashman said:


> Then use the FORFILES command.


I must need some kind of add-on? FORFILES is not a valid command for me... or perhaps it is because I am running XP?


----------



## foxidrive (Oct 20, 2012)

XP didn't ship with forfiles.exe but it is available for free download from Microsoft.

Vista and later come with forfiles by default.


----------

