Why is a enviroment variable in a for loop not updated?

G

Guest

Below, I have a script that is uppose to update an enviroment variable with a
list of files. However FILELIST does not update correctly. Can anyone tell me
why? This is very similar to some script code that I have not been able to
get to work.

@setlocal enabledelayedexpansion
@SET FILELIST=NOFILES
@set test=buddy
@set test=buddy1;%test%
@set test=buddy2;%test%



@for %%f in (*.txt) do @(

@echo %FILELIST%
@echo %%f
@set FILELIST=%%f;%FILELIST%;test3


)



echo %FILELIST%
echo %test%
@endlocal
 
V

Vanguard

Buddy Lott said:
Below, I have a script that is uppose to update an enviroment variable
with a
list of files. However FILELIST does not update correctly. Can anyone
tell me
why? This is very similar to some script code that I have not been
able to
get to work.

@setlocal enabledelayedexpansion
@SET FILELIST=NOFILES
@set test=buddy
@set test=buddy1;%test%
@set test=buddy2;%test%



@for %%f in (*.txt) do @(

@echo %FILELIST%
@echo %%f
@set FILELIST=%%f;%FILELIST%;test3


)



echo %FILELIST%
echo %test%
@endlocal


Run the following command at a DOS prompt:

cmd /?

Now look at the /v:blush:n mode for when environment variable delayed
expansion is enabled. See what it says to use for the variable
delimiter character? It isn't the percent sign. If you want to force
the environment variable to get set within the shell for the for-loop
rather than after when the for-loop exits (i.e., immediate expansion
versus delayed expansion) then use the exclamation character to delimit
environment vars within the for-loop's body. Since %f (as %%f is set at
the start of the each loop, you can still use %%f within the body of the
for-loop to get the next value to be used within the for-loop. But the
FILELIST variable is not initialized or changed on each loop so
%FILELIST% refers to the value that was set before the shell for the
for-loop was established (i.e., you will keep using the old value of
FILELIST). So try changing %FILELIST% to !FILELIST!.

That means you will need to use the /v:blush:n switch when loading the
command shell that then runs the .bat or .cmd file. If something like:

set testvar=test
set testvar=!test!string

returns "!test!string" instead of "teststring" then you know that you
need to have that .bat file call itself via:

if not "%testvar%" == "teststring" (
echo <warning messages>
echo Retrying batch file in correct environment
cmd /v:blush:n /c %0 %*
goto BreakOut
)
<here is the script you wanted to run>
:BreakOut
<do cleanup>

Actually I should use "cmd /v:blush:n /c %0 2ndRun %*" and then test if %1 is
"2ndRun" or some other trigger string so that I don't get stuck in a
repeat reexecute looping of the .bat file calling itself in case the
retry didn't work - but, so far, "cmd /v:blush:n" has successfully enabled
the delayed expansion mode but that's because I test on Windows XP. If
I were to distribute this script to others then I would need that check
to ensure they don't get stuck in the .bat file continuously reexecuting
itself should their cmd.exe not support delayed expansion mode (but then
they would have to change cmd.exe to command.com which doesn't have the
/v switch, anyway, and the script would abort out due to not finding the
cmd.exe file).

I haven't used the setlocal command so it might be used to enable
delayed expansion within the .bat file without the need to call itself
again under the correct environment. However, whether you do as I have
or use setlocal, you need to distinguish between when you want delayed
or immediate expansion of environment variables by using a different
delimiter character (i.e., % for delayed and ! for immediate). I use
the .bat file reexecuting itself because I'm not sure under which
versions of Windows the setlocal command is available. I think setlocal
became available as of Windows XP but some of my scripts are ran on
other users' hosts and I won't know if setlocal will be available to
them.
 
G

Guest

What I thought was a simple example turned out to be TOO simple .. The batch
file code I am trying to get working is :

@FOR /R %%f IN (*.cpp *.c) DO (
if exist "%%~nf.lnt". SET FILE_SPECIFIC_CONFIG="%%~pf%%~nf.lnt".
if exist "%~p1\pclint.lnt". SET DIR_SPECIFIC="%~p1\pclint.lnt".
lint-nt "-os(%%~pf%%~nf.lint)" %LINT_INCLUDE% %DIR_SPECIFIC%
%FILE_SPECIFIC_CONFIG% u:\Projects\BAC\B_BC\sw\BC.lnt -u %%f
)
@goto :EOF


I tried using the '!' on the lint-nt line, but it doesn't work. I have tried
several variations, but the just is that the expansion of DIR_SPECIFC and
FILE_SPECIFC never seems to happen on the lint-nt line. Any other ideas?
 
V

Vanguard

in message
What I thought was a simple example turned out to be TOO simple .. The
batch
file code I am trying to get working is :

@FOR /R %%f IN (*.cpp *.c) DO (
if exist "%%~nf.lnt". SET FILE_SPECIFIC_CONFIG="%%~pf%%~nf.lnt".
if exist "%~p1\pclint.lnt". SET
DIR_SPECIFIC="%~p1\pclint.lnt".
lint-nt "-os(%%~pf%%~nf.lint)" %LINT_INCLUDE%
%DIR_SPECIFIC%
%FILE_SPECIFIC_CONFIG% u:\Projects\BAC\B_BC\sw\BC.lnt -u %%f
)
@goto :EOF


I tried using the '!' on the lint-nt line, but it doesn't work. I have
tried
several variations, but the just is that the expansion of DIR_SPECIFC
and
FILE_SPECIFC never seems to happen on the lint-nt line. Any other
ideas?


Precede the for-loop with setting the DIR_SPECIFIC and
FILE_SPECIFIC_CONFIG variables (just so you can see if they got changed
since blank output can be confusing for undefined vars). Then precede
the lint-nt line with an echo to show what are the values of those vars.
For now, remark out the lint-nt line (no point in trying to execute it
if it doesn't work yet).

set DIR_SPECIFIC=UNDEFINED
set FILE_SPECIFIC_CONFIG=UNDEFINED
FOR ... DO (
...
echo DIR="!DIR_SPECIFIC!", FILECFG="!FILE_SPECIFIC_CONFIG!"
rem lint-nt ...
)

What do you get? Is the same "UNDEFINED" string (the initial value)
shown in the echo command through each pass through the for-loop?

Just in case setlocal is not doing what you expect (like you see "!" in
the output of the above echo command), what happens when you executed
the .bat file under "cmd.exe /v:blush:n /c <batfile>"?

I don't remember what were the conditions but I do remember having to
use a 'set' command on vars that were previously changed within a
for-loop, something like:

for ... do (
<something that changes the VAR variable>
set fVAR=!VAR!
<use !fVAR! in other statements in for-loop>
)
 
G

Guest

I tried every thing you suggested and it still did not work. The behavior was
the same whether I tried the 'cmd' command or ran straight from a command
prompt. When I set the variables before the loop, I get that value in the
echo statement at the end of the loop.
 
V

Vanguard

in message
I tried every thing you suggested and it still did not work. The
behavior was
the same whether I tried the 'cmd' command or ran straight from a
command
prompt. When I set the variables before the loop, I get that value in
the
echo statement at the end of the loop.


Tis weird. I ran the following test.bat file to see what I would get:

@echo off
cls

set tdir=D:\_DOWNLOAD

set tvar=UNDEFINED
for /r %tdir% %%I in (*.exe *.msi) do (
if /i "%%~xI" == ".exe" set tvar=EXE file is %%I
if /i "%%~xI" == ".msi" set tvar=MSI file is %%I
echo.
echo %tvar%
echo !tvar!
)
echo.
echo Final tvar = %tvar%

This was ran under "cmd /v:blush:n". The directory specified by tdir was a
place where I temporary save downloaded files and is smaller than most
of my other directories (I didn't want a huge amount of output). It
contains .exe, .msi, .reg, .txt, .zip and other filetypes. I wanted the
for-loop only to list the .exe and .msi files.

I set tvar to "UNDEFINED" to see when that instance of it got changed.
The for-loop creates its own shell and why on each pass the "echo
%tvar%" kept outputting "UNDEFINED". It wasn't until the for-loop
exited when tvar in the parent shell got updated to show the last value
obtained inside the for-loop. So my output looked like (note that
"echo." doesn't work inside a for-loop):

UNDEFINED
EXE file is <file1>.exe
 
G

Guest

Maybe I am chacing a ghost .. or maybe I should make sure I am testing what I
think I am testing ...

I ran this:

setlocal EnableDelayedExpansion
@FOR /R %%f IN (*.cpp *.c) DO (
@set FILE_SPECIFIC=FILE_UNDEFINED
@set DIR_SPECIFIC=DIR_UNDEFINED
@if exist "%%~nf.lnt" SET FILE_SPECIFIC="%%~pf%%~nf.lnt"
@if exist "%%~pf\pclint.lnt" SET DIR_SPECIFIC="%%~pf\pclint.lnt"
echo !FILE_SPECIFIC! 22 %FILE_SPECIFIC%
echo !DIR_SPECIFIC! 33 %DIR_SPECIFIC%
lint-nt "-os(%%~pf%%~nf.lint)" %LINT_INCLUDE% !DIR_SPECIFIC!
!FILE_SPECIFIC! u:\Projects\BAC\B_BC\sw\BC.lnt -u %%f
)
echo !FILE_SPECIFIC! = %FILE_SPECIFIC%
echo !DIR_SPECIFIC! = %DIR_SPECIFIC%
endlocal
@goto :EOF

I saw this as part of the output:

echo !FILE_SPECIFIC! 22
echo !DIR_SPECIFIC! 33
lint-nt "-os(\Projects\BAC\B_BC\sw\app\ControlBasic\cb.lint)" C:\LINT\lnt
!DIR_SPECIFIC! !FILE_SPECIFIC! u:\Projects\BAC\B_BC\sw\BC.lnt -u
U:\Projects\BAC\B_BC\sw\app\ControlBasic\cb.cpp
)
"\Projects\BAC\B_BC\sw\app\ControlBasic\cb.lnt" 22
"\Projects\BAC\B_BC\sw\app\ControlBasic\\pclint.lnt" 33

U:\Projects\BAC\B_BC\sw\app\ControlBasic>(


I finally noticed that the ECHO commands are echoed with the !FILE_SPECIFIC!
and !DIR_SPECIFIC! but the output from the ECHO looks correct! Which means my
code is probably working . I just need to look at other lint-nt output
instead of the command echo to see if it working.

THANKS!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top