windowsfor-loopbatch-filemultiple-choice

Batch How to avoid a same 2nd FOR loop?


I have created a batch script to backup some subfolders from a path A to a path B (Z:\Folder1\… > U:\Backup\…).

The script lists the subfolders inside path A and increments a number for each of them. Then, I just have to enter the number(s) of the subfolder(s) I want to backup and xcopy does the rest.

The problem is that sometimes I have thousands of subfolders in path A and only a few to backup (10 or 15).

What I would like is that once I enter the number of these folders, it will go straight to the backup without having to loop all the subfolders inside path A AGAIN (which take time).

Here is my batch :

@echo off

setlocal EnableDelayedExpansion

rem Script for backuping some subfolders from path A to path B

set BackupLocation=U:\Backup
set subfolder_no=1

FOR /F "delims=" %%a IN ('dir /b "Z:\Folder1\*"') DO ( 

    set subfolder=%%a

    if defined subfolder (
        echo !subfolder_no! !subfolder!
        set /a subfolder_no+=1
        
    )
    
)
    
set /a subfolder_no=%subfolder_no%-1
set /a index=0
set /a choice=-1

echo.
set /p choice=Enter the number(s) of the subfolder(s) you want to backup: 

FOR /F "delims=" %%a IN ('dir /b "Z:\Folder1\*"') DO ( 

    set subfolder=%%a

    if defined subfolder (
        set /a index+=1
    )

FOR %%f IN (%choice%) DO if %%f==!index! (

echo.
echo Backuping subfolder !subfolder!

xcopy "Z:\Folder1\!subfolder!" "%BackupLocation%\!subfolder!\" /e /i /y

)
)

echo.
pause

exit

How can I do this ? Is it possible to get the subfolders' name from their matching number and store them in variables or something ?

Thanks a lot for your help !


Solution

  • Here's an example which only enumerates the directories once.

    Please note, whilst it technically answers your question, and performs the task you require of it, this version is designed to work as intended on Windows 10. The specific part you asked about works in other versions too, but the :BackUp labelled section uses a new and undocumented Windows 10 feature of the sort command, to return only unique items from the selection list. Without that, your end user could tehnically provide the same number multiple times, and thus trigger multiple backups of the same directory. As this part of the code is technically outside of the scope of your question, I will leave it up to you to modify the code section yourself, should you be deploying this on older Operating Systems.

    @Echo Off
    SetLocal EnableExtensions DisableDelayedExpansion
    
    Rem Script for backing up some subdirectories of a Source path to a Backup path.
    Set "SourceLocation=Z:\Folder1"
    Set "BackupLocation=U:\Backup"
    
    If Not Exist "%Sourcelocation%\." Exit /B
    If Not Exist "%Backuplocation%\." Exit /B
    
    :ShowSet
    For /F "Delims==" %%G In ('"(Set subdirectory[) 2>NUL"') Do Set "%%G="
    Set "index=0"
    For /F "EOL=? Delims=" %%G In ('Dir /B /A:D /O:N "%SourceLocation%" 2^>NUL'
    ) Do (Set /A index += 1
        Set "subdirectory=%%G"
        SetLocal EnableDelayedExpansion
        Echo !index! !subdirectory!
        For /F "Tokens=1,*" %%H In ("!index! !subdirectory!") Do (EndLocal
            Set "subdirectory[%%H]=%%I"))
    If Not Defined subdirectory[1] Exit /B
    
    :Select
    Echo(
    Echo Please type the number(s) for the subdirectories you want to backup,
    Echo(
    Echo For multiple selections please separate each with spaces e.g. 1 3 6
    Echo For none please type 0 or press [ENTER].
    Set "selection=0"
    Set /P "selection=>"
    Set "selection=%selection:"=%"
    Set "selection=%selection:)=%"
    If Not Defined selection GoTo Select
    If "%selection%" == "0" GoTo :EOF
    (Set selection) | "%SystemRoot%\System32\findstr.exe"^
     /X /R /C:"selection=[0123456789 ][0123456789 ]*" 1>NUL || GoTo Select
    Set "selection=%selection% "
    
    :BackUp
    For /F %%G In (
        '"(Echo(%selection: =^&Echo(%) | "%SystemRoot%\System32\sort.exe" /Unique"'
    ) Do If Not Defined subdirectory[%%G] (Echo Selection %%G was not valid) Else (
        SetLocal EnableDelayedExpansion
        Echo(&Echo Backing up subdirectory %%G !subdirectory[%%G]!
        "%SystemRoot%\System32\Robocopy.exe" ^
         "%SourceLocation%\!subdirectory[%%G]!" ^
          "%BackupLocation%\!subdirectory[%%G]!" /E /NC /NDL /NJH /NJS /NS ^
           | %SystemRoot%\System32\find.exe /V " (0x00000005) "
        EndLocal)
    Pause
    

    In the :BackUp section, I have used Robocopy.exe instead of the deprecated xcopy.exe utility you had used.

    If you wish to still use xcopy.exe, replace:

        "%SystemRoot%\System32\Robocopy.exe" ^
         "%SourceLocation%\!subdirectory[%%G]!" ^
          "%BackupLocation%\!subdirectory[%%G]!" /E /NC /NDL /NJH /NJS /NS ^
           | %SystemRoot%\System32\find.exe /V " (0x00000005) "
    

    with:

        "%SystemRoot%\System32\xcopy.exe" ^
         "%SourceLocation%\!subdirectory[%%G]!" ^
          "%BackupLocation%\!subdirectory[%%G]!\" /E /I /Y