You are not logged in.

#1 17 Apr 2016 00:35

Rekrul
Member
Registered: 17 Apr 2016
Posts: 98

Why don't normal variable function work in a FOR loop???

I'm trying to write a relatively simple script under Windows XP (Yes I know; DOOM! GLOOM! END OF THE WORLD!!!) which uses a FOR loop to process all the files of certain type in a directory, and for the life of me, I can't figure out what I'm doing wrong. Simple variable functions that normally work fine produce an error when used inside the loop.

This works;

set test1=hi
set test2=there
set test3=%test1%%test2%

This does not;

for %%G in (*.bin) do (
 set test1=hi
 set test2=there
 set test3=%test1%%test2%
)

Running it produces the error message;

.bintest was unexpected at this time.

I've searched Google and can't find any mention of the fact that simple variable functions don't work inside a FOR loop. If I remove the third SET line, it works and both TEST1 and TEST2 are set properly. However trying to concat them together into TEST3 makes it fail.

This also fails;

for %%G in (*.bin) do (
 set test1=hi
 set test2=there
 echo %test1%%test2%
)

Of course you're probably wondering why I would want to perform the same variable operations for each loop. Well, I actually had something much more complex in mind which involved manipulating %%G in various ways, but that didn't work at all. So then I tried the simplest thing I could think of and even that doesn't work.

Am I doing something wrong, or is it not possible to use normal variable functions in a FOR loop?

Offline

#2 17 Apr 2016 02:21

Shadow Thief
Member
Registered: 12 Jul 2012
Posts: 205

Re: Why don't normal variable function work in a FOR loop???

Classic delayed expansion problem. Don't feel bad; literally everybody who codes in batch will eventually encounter this.

Basically, when a batch script is run, the interpreter expands variables to their values. When you enable delayed expansion, you can indicate to the interpreter that certain variables need to keep their variable-ness (for lack of a better word).

REM you only need to put this in your script once at the beginning, not every time you need to use delayed expansion
setlocal enabledelayedexpansion

for %%G in (*.bin) do (
    set test1=hi
    set test2=there
    echo !test1!test2!
)

Offline

#3 17 Apr 2016 04:13

Rekrul
Member
Registered: 17 Apr 2016
Posts: 98

Re: Why don't normal variable function work in a FOR loop???

Shadow Thief wrote:

Classic delayed expansion problem. Don't feel bad; literally everybody who codes in batch will eventually encounter this.

Basically, when a batch script is run, the interpreter expands variables to their values. When you enable delayed expansion, you can indicate to the interpreter that certain variables need to keep their variable-ness (for lack of a better word).

Thank you for the example, I added it to my script and made it work.

I read a couple pages explaining delayed expansion and I still don't understand exactly how it works or why variable functions in a loop don't work as expected. Or frankly, why anyone would think it was a good idea to make delayed expansion the default rather than making it an option. Then again, Microsoft has a long history of making stuff unintuitive...

Basically my take-away from this is to add the line setlocal enabledelayedexpansion at the start and use !variable! instead of %variable%, which seems to work.

Offline

#4 18 Apr 2016 08:15

bluesxman
Member
From: UK
Registered: 29 Dec 2006
Posts: 1,129

Re: Why don't normal variable function work in a FOR loop???


cmd | *sh | ruby | chef

Offline

#5 18 Apr 2016 11:44

Rekrul
Member
Registered: 17 Apr 2016
Posts: 98

Re: Why don't normal variable function work in a FOR loop???

bluesxman wrote:

FYI

Yes, I read that page and I still don't understand it. It is completely counter-intuitive that absolute variable definitions aren't absolute. I also don't understand why this is the default in a FOR loop rather than being an option.

I mean under what precise conditions would you want a variable to NOT equal the value you set it to? Did someone at Microsoft actually say to themselves "Hmm, what we need is a way for scripts to completely ignore variable definitions!"

Why wouldn't they make it so that %name% is always a normal variable and !name! is always delayed expansion? It's simple, intuitive and would behave exactly the way people expect. Instead of "Use %name% for most things, but if you're trying to use variables inside a FOR loop, then you have to use !name!."

Is there a list somewhere of all the places that normal variable function won't work as expected or is it just trial and error?

Offline

#6 18 Apr 2016 14:41

Shadow Thief
Member
Registered: 12 Jul 2012
Posts: 205

Re: Why don't normal variable function work in a FOR loop???

It's anytime you set a variable inside of parentheses

Offline

#7 18 Apr 2016 19:03

Rekrul
Member
Registered: 17 Apr 2016
Posts: 98

Re: Why don't normal variable function work in a FOR loop???

Shadow Thief wrote:

It's anytime you set a variable inside of parentheses

It still seems like a completely backwards way of doing things. Why would you ever want a variable to NOT display its actual value/contents?

Offline

#8 19 Apr 2016 14:36

foxidrive
Member
Registered: 04 Apr 2013
Posts: 339

Re: Why don't normal variable function work in a FOR loop???

Rekrul wrote:

It still seems like a completely backwards way of doing things.

It breaks the ! character unless certain steps are taken.

This is part of the whole 'poison characters for batch files' thing.

Offline

#9 03 May 2016 14:36

elias
Member
Registered: 03 May 2016
Posts: 12

Re: Why don't normal variable function work in a FOR loop???

Rekrul wrote:
Shadow Thief wrote:

It's anytime you set a variable inside of parentheses

It still seems like a completely backwards way of doing things. Why would you ever want a variable to NOT display its actual value/contents?

I think they want you to explicitly use delayed expansion for performance reasons.

It took me a great deal to explain this concept and demystify it in my Batchography book.


Book: Batchography - The Art of Batch Files Programming

Offline

#10 30 May 2016 10:37

Rekrul
Member
Registered: 17 Apr 2016
Posts: 98

Re: Why don't normal variable function work in a FOR loop???

OK, I'm back...

Using the examples and help posted here, I was able to get my script working and it seemed foolproof. After a period of not using it, I used it again the other day and I discovered that it fails on any filename with an exclamation point in it.

Here is a bit of sample code which I've lifted from my longer script and simplified;

setlocal enabledelayedexpansion
for %%F in (*.bin) do (
 7za a "%%F" "%%~nF.7z"
 set name=%%~nF
 set name="!name:USA=U!"
 echo !name!
)

As you can see, I set delayed expansion and use ! rather than % to mark the normal variables. Then for all filenames ending in .bin it packs them, sets the variable name equal to the filename, minus the extension, then it uses a replace expression to change any occurance of the string "USA" to "U", then it prints the variable.

Unfortunately if any filenames contain exclamation points this script fails spectacularly! Not only do the variables not have the exclamation points, but for some reason, it also packs every file in the directory into a 7zip archive with the extention .BIN, then it packs that into a 7zip archive with the proper extension! I've verified that this isn't 7zip's fault as I can't make it happen outside of a script, no matter how badly I bungle the command line. Without including a wildcard, the worst it does is create an empty archive.

Is there any way to modify the above fragment to account for filenames that have exclamation points in them? I already tried to replace %%F with !!F and as you might guess, it didn't work. The few examples I've found on the web assume that you're setting the variable contents yourself and can escape the characters. I can't seem to find any that show what to do when the variable is being set from a filename.

Offline

#11 08 Jun 2016 20:30

BlueBearr
New Member
Registered: 08 Jun 2016
Posts: 2

Re: Why don't normal variable function work in a FOR loop???

This seems to for me.

for %%F in (*.bin) do (
 7za a "%%~nF.7z" "%%F"
 setlocal enabledelayedexpansion
 set name=%%~nF
 set name="!name:USA=U!"
 echo !name!
 setlocal DISABLEDELAYEDEXPANSION
)

Offline

Board footer

Powered by