verifier
verifier

Reputation: 3

Endlocal & "set var" not working as expected in "for" loop

I'm doing a job, copying files from one location to another location using BATCH file. I split my statements into three parts, one program driver, one for generating file list under each sub-directory, and one for checking file name & doing actual copy stuff.

1.PROGRAM DRIVER

IF EXIST TEMP.TXT DEL TEMP.TXT
CD>TEMP.TXT
set /p ROOT=<TEMP.TXT

rem PARA is the date to copy
SET PARA=2013-08-06
ECHO %PARA%
CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO (    ::COPY SUB-LOGIC FILE TO EACH SUB-DIRECTORY
    ECHO NOW IN %%A
    CD %%A
    XCOPY "%ROOT%\WORK.BAT" . /K /Y
    XCOPY "%ROOT%\CORE.BAT" . /K /Y
    ECHO LOOP OUT.
)

CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO (
    ECHO NOW IN %%A
    CD %%A
    CALL WORK.BAT        ::GENERATING FILE LIST
    ECHO LOOP OUT.
)

CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO (
    ECHO NOW IN %%A
    CD %%A
    CALL CORE.BAT        ::DOING COPY STUFF
    ECHO LOOP OUT.
)

PAUSE

2.WORK.BAT

IF EXIST FILE.TXT DEL FILE.TXT
FOR %%B IN (*.wav) DO ECHO %%~nxB>>FILE.TXT

3.COPYING STUFF

FOR %%F IN ("%CD%") DO SET CURDIR=%%~nxF
IF NOT EXIST FILE.TXT GOTO END
SET CCC="FALSE"  ::IF NO CCC DECLARED HERE,BELOW FOR LOOP WILL BE SKIPPED
PAUSE
FOR /F %%C IN (FILE.TXT) DO (
    SETLOCAL
    SET RES="FALSE"
    IF "%%C" GEQ "CH201_00000000_000.WAV" SET RES="TRUE"
    IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
         SET RES="TRUE"
    ) ELSE ( SET RES="FALSE")
    ENDLOCAL& SET CCC=%RES%    *::VAR CCC NOT UPDATED*
    PAUSE
    IF %CCC% EQU "TRUE" (
        IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
        XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
    )
)
:END
ECHO LOOP OUT

My question is, why my "ENDLOCAL & SET" statement not working, i.e., NULL each time, as pictures show. How can I change my statements to make it work as expected?

First image

Second image


I changed part 3 to

FOR %%F IN ("%CD%") DO SET CURDIR=%%~nxF
IF NOT EXIST FILE.TXT GOTO END
SET "RES="
PAUSE
FOR /F %%C IN (FILE.TXT) DO (
    SET "RES="
    IF "%%C" GEQ "CH201_00000000_000.WAV" SET "RES=Y"
    IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
        SET "RES=Y"
    ) ELSE ( SET "RES=" )
    PAUSE
    IF DEFINED RES (
            IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
            XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
    )
)

It seems that RES always defined, even FILENAME is in specified ranges. In this case, it copied wrong files.

New runtime result

Upvotes: 0

Views: 336

Answers (1)

Magoo
Magoo

Reputation: 79983

in (3)

FOR /F %%C IN (FILE.TXT) DO (
    SETLOCAL
    SET RES="FALSE"
    IF "%%C" GEQ "CH201_00000000_000.WAV" SET RES="TRUE"
    IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
         SET RES="TRUE"
    ) ELSE ( SET RES="FALSE")
    ENDLOCAL& SET CCC=%RES%    *::VAR CCC NOT UPDATED*
    PAUSE
    IF %CCC% EQU "TRUE" (
        IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
        XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
    )
)

Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).

Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.

Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.

Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.

Where flags are involved, the situation changes again. set "flag=" will ensure a flag is cleared. set "flag=somethingelse" will ensure it is set (the value is not relevant.) Using if defined flag (doiftrue) else (doiffalse) works on the run-time (current) status of flag - not the parse-time value.

Hence, I suggest you change your processing, setting ccc to either nothing with a set "ccc=" statement or something with a set "ccc=y" and you can then test for true/false using if [not] defined ccc

The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".


(on revised code)

Your tests are incorrect.

res will not be set to Y with value CH145... against CH201... But it will be set to Y in the LEQ test as CH145... is lestt than or equal to CH300...

You may either cascade the setting:

if "%%C" GEQ "CH201..." IF "%%C" LEQ "CH300..." set "res=Y"

or gate the test

IF "%%C" GEQ "CH201_00000000_000.WAV" SET "RES=Y"
if defined res IF "%%C" GTR "CH300_FFFFFFFF_FFF.WAV" SET "RES=" 

Upvotes: 1

Related Questions