Search code examples
windowsbatch-filexcopy

batch file to copy only one of filetype for each subfolder to another folder


here is my code:

xcopy "C:\Users\Me\Desktop\data\*.mtl" "C:\Users\Me\Desktop\mtl" /s /e

What it does is copy all the files of filetype .mtl from the subfolders under the data folder, and copy it to the mtl folder in the desktop while retaining its folder structure at the same time.

Which is good, but my goal is to limit the file selection for each subfolder to only one of the filetype .mtl. So instead of copying all .mtl files in each subfolder, it would copy one .mtl file for each subfolder.

How can I do this?


Solution

  • @ECHO OFF
    SETLOCAL
    SET "sourcedir=U:\sourcedir"
    SET "destdir=U:\destdir"
    
    xcopy /T /E "%sourcedir%\*.mtl" "%destdir%\"
    SET "source=:"
    FOR /f "delims=" %%a IN (
     'xcopy /L /s "%sourcedir%\*.mtl" "%destdir%\" '
     ) DO (
     CALL :chksubdir "%%a"
    )
    
    GOTO :EOF
    
    :chksubdir
    ECHO "%~1"|FIND "\">NUL
    IF ERRORLEVEL 1 GOTO :EOF 
    IF /i "%source%"=="%~dp1" GOTO :EOF 
    SET "source=%~dp1"
    CALL SET "sub=%%source:%sourcedir%=%%"
    COPY "%~1" "%destdir%%sub%%~nx1" >NUL 2>nul
    GOTO :eof
    

    You would need to change the settings of sourcedir and destdir to suit your circumstances.

    The first step is to use the /t option of xcopy to create the destination subtree.

    Having set source to a dummy value, using the subroutine chksubdir to process each line of XCOPY /L /S for the files. This is a list-only, and does not actually do the copy.

    The subroutine checks whether the supplied parameter contains \ as the very last line of the xcopy /L is a count-report. If no \ is found, exit.

    Otherwise, match source to the drive+path of the selected file. If these are not-equal, then a new directory has been found, otherwise skip this file.

    Set source to the new subdirectory name and then set sub to that full name minus the relative root, giving the subdirectory string below the relative root.

    String it all together to generate a simple copy command.