Search code examples
batch-filegotodelayedvariableexpansion

Why the loop is not running as expected?


I have folders like E:\Backups\code\Hazard\test1 ... testn

And inside these test folders something like E:\Backups\code\Hazard\test1\it0 ... itn

The root folder is E:\Backups\code from where the code runs.

The below code runs on each subfolders and copies summary.yml from it0 folder to latest it(n) folder.

Why the code runs just for test1 folder and then hangs?

setlocal ENABLEDELAYEDEXPANSION

set root=%cd%
for /D %%X in (%root%\*) do (
    echo %%X
    cd  %%X

    for /D /r %%b in (*) do ( 
        cd  %%b

        echo %%b

        for /f "tokens=1,2,*" %%a in ('robocopy . . file.txt /l /nocopy /is /s /nc /ns /ts /ndl /njh /njs ^| sort /r') do set "lastFolder=%%~dpc" & goto :done
:done
        echo Last folder : %lastFolder%

        for /d    %%j in (*) do  (
            if /i "%%~nj"=="it0" COPY %%j\summary.yml %lastFolder% 
        )
        cd ..
    )
)

Solution

  • There are two main problems in the code:

    • If goto is used inside a for loop, the loop is cancelled
    • If you set a variable inside a block of code (code inside parenthesis), to retrieve the value of the variable inside the same block of code you need delayed expansion, enabling it with setlocal enabledelayedexpansion and changing the syntax used to retrieve the value in the variable from %var% into !var!.

    But

    • the goto can be removed as indicated in the previous answer,
    • the delayed expansion is not needed. Instead of storing the value from the for replaceable parameter inside a variable, just use the replaceable parameter

    Not tested, but more or less

    @echo off
        setlocal enableextensions disabledelayedexpansion
    
        rem E:\Backups\ code   \  Hazard \ test1 \ it0 ... itn
        rem             ^root     ^ %%X    ^ %%Y           ^ %%~dpc
    
        for /D %%X in ("*") do for /D %%Y in ("%%~fX\*") do for /f "tokens=1,2,*" %%a in ('
            robocopy "%%~fY." "%%~fY." file.txt /l /nocopy /is /s /nc /ns /ts /ndl /njh /njs 
            ^| sort /r 2^>nul
            ^| cmd /q /v /c "(set /p .=&echo(!.!)"
        ') do copy "%%~fY\it0\summary.yml" "%%~dpc."
    

    Being E:\Backups\code the current active directory:

    • %%X will enumerate the folders under E:\Backups\code (Hazard)
    • %%Y will enumerate the folders under E:\Backups\code\Hazard (testn)
    • %%a executes a robocopy command to locate the folder containing the latest file.txt file
    • sort /r sorts the list of files in descending order so the latest file is the first in the list
    • cmd retrieves and outputs only the first line
    • With all the information available in the several for replaceable parameters, execute the indicated copy command.