1. Computer problem? Tech Support Guy is completely free -- paid for by advertisers and donations. Click here to join today! If you're new to Tech Support Guy, we highly recommend that you visit our Guide for New Members.

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

Discussion in 'DOS/Other' started by ttx336, Dec 22, 2012.

Thread Status:
Not open for further replies.
Advertisement
  1. ttx336

    ttx336 Thread Starter

    Joined:
    Nov 7, 2012
    Messages:
    49
    Code:
    @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

    Code:
    @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
     
  2. Squashman

    Squashman Trusted Advisor

    Joined:
    Apr 4, 2003
    Messages:
    19,786
    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.
     
  3. ttx336

    ttx336 Thread Starter

    Joined:
    Nov 7, 2012
    Messages:
    49
    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
     
  4. foxidrive

    foxidrive Banned

    Joined:
    Oct 20, 2012
    Messages:
    793
    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.
     
  5. ttx336

    ttx336 Thread Starter

    Joined:
    Nov 7, 2012
    Messages:
    49

    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.

    Code:
    @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
     
  6. Squashman

    Squashman Trusted Advisor

    Joined:
    Apr 4, 2003
    Messages:
    19,786
    Then use the FORFILES command.
     
  7. foxidrive

    foxidrive Banned

    Joined:
    Oct 20, 2012
    Messages:
    793
    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.

    Code:
    @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. :)
     
  8. ttx336

    ttx336 Thread Starter

    Joined:
    Nov 7, 2012
    Messages:
    49
    Code:
    @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!
     
  9. foxidrive

    foxidrive Banned

    Joined:
    Oct 20, 2012
    Messages:
    793
    Well done.
     
  10. ttx336

    ttx336 Thread Starter

    Joined:
    Nov 7, 2012
    Messages:
    49
    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
     
  11. ttx336

    ttx336 Thread Starter

    Joined:
    Nov 7, 2012
    Messages:
    49
    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? :rolleyes:
     
  12. foxidrive

    foxidrive Banned

    Joined:
    Oct 20, 2012
    Messages:
    793
    XP didn't ship with forfiles.exe but it is available for free download from Microsoft.

    Vista and later come with forfiles by default.
     
  13. Sponsor

As Seen On
As Seen On...

Welcome to Tech Support Guy!

Are you looking for the solution to your computer problem? Join our site today to ask your question. This site is completely free -- paid for by advertisers and donations.

If you're not already familiar with forums, watch our Welcome Guide to get started.

Join over 733,556 other people just like you!

Thread Status:
Not open for further replies.

Short URL to this thread: https://techguy.org/1081966

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice