ABD
ABD

Reputation: 23

Batch file to copy file from specific sub folder inside a folder to destination folder

I have a folder structure like his

folder1-------|
              |123456------123.txt
                          abc.txt
              |234567------fgt.txt
                           234.txt
              |abc---------ytr.txt
                           1234.txt

I need to copy files from Main folders sub directories if the sub folder has a length of 6(only numbers) . So .txt files from 123456,234567 will be copied and abc will not be copied.

I have tried using wildcards but not succeed yet. Thanks in advance.

>xcopy /s "C:\Users\xxx.xxx\Desktop\folder1\*\*.txt" "C:\Users\xxx.xxx\Documents\New folder" /l /D:09-09-2019

Upvotes: 1

Views: 329

Answers (3)

user7818749
user7818749

Reputation:

Ok, so here is an example:

@echo off
setlocal enabledelayedexpansion

for /f %%i in ('dir "C:\Users\xxx.xxx\Desktop\folder1\" /b /ad') do (
  set "str=#%%i"
  set "len=0"
  for %%a in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
    if "!str:~%%a,1!" neq "" (
       set /a "len+=%%a"
       set "str=!str:~%%a!"
       if !len! equ 6 if 1%%i equ +1%%i echo %%i is !len! characters   
     )
   )
)

This will do a dir of the directories inside the path you give it. It will then test the length of the string, if the length is 6 characters, it will then test if the string is numeric, if true, it will echo the string (folder name) and the length of it. You should then test it as is and if it gives you the required output, you can replace echo portion with your copy string.

So your final solution will be something like:

@echo off
setlocal enabledelayedexpansion
set /p "mydate=Enter Date (format dd-mm-yyyy): "
for /f %%i in ('dir "C:\Users\xxx.xxx\Desktop\folder1\" /b /ad') do (
  set "str=#%%i"
  set "len=0"
  for %%a in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
    if "!str:~%%a,1!" neq "" (
       set /a "len+=%%a"
       set "str=!str:~%%a!"
       if !len! equ 6 if 1%%i equ +1%%i xcopy "C:\Users\xxx.xxx\Desktop\folder1\%%i\*.txt" "C:\Users\xxx.xxx\Documents\New folder" /D:!mydate! 
     )
   )
)

Upvotes: 1

aschipfl
aschipfl

Reputation: 34979

Here is yet another method to achieve what you want (see all the explanatory rem remarks):

@echo off
rem // Use a `for /D` loop to iterate through all immediate sub-directories in the given root directory:
for /D %%I in ("%UserProfile%\Desktop\folder1\*") do (
    rem // Store path and name of currently iterated directory in variables:
    set "DIRECTORY=%%~I" & set "NAME=%%~nxI"
    rem // Toggle delayed expansion to be able to write and to read a variable within the same block of code:
    setlocal EnableDelayedExpansion
    rem // Check if directory name holds more than 5 characters:
    if not "!NAME:~5!" == "" (
        rem // Check if directory name holds not more than 6 characters:
        if "!NAME:~0,6!" == "!NAME!" (
            rem // The directory name is exactly 6 characters long.
            rem // Check whether the directory name consists of decimal figures by (mis-)using a `for /F` loop:
            set "FLAG=" & for /F "tokens=1 delims=0123456789 eol=0" %%J in ("!NAME!") do set "FLAG=#"
            rem // The flag variable has not been set, hence the directory name consists of decimal figures:
            if not defined FLAG (
                rem // Do the actual copy job at this point:
                xcopy /I /Y /D:09-09-2019 "!DIRECTORY!\*.txt" "!UserProfile!\Documents\New Folder"
            )
        )
    )
    endlocal
)

You were trying to use wildcards not only in the last element of a path, which cannot be done (in Windows), but you can use a for /D loop to resolve the wildcards in upper directory levels, as demonstrated in the script.

The script uses ~-modifiers (which are the same for for meta-variables like %%I and for argument references like %1) to get the pure name of the currently iterated directory: %%~nxI.

To determine whether or not the directory name is exactly six (6) characters long, sub-string expansion is applied.

To determine whether or not the directory name consists of decimal digits only, a for /F loop is (mis-)used: for /F splits strings into parts at given delimiter characters (option delims); since all decimal digits are defined as delimiters, a directory named 1a2b3c would be split into the parts a, b and c (a becomes assigned to %%J then due to tokens=1, the other parts become dismissed), but a directory name 123456 leaves nothing behind since this is a delimiter-only string, in which case the for /F loop does not iterate at all. Together with a flag-like variable FLAG that becomes set in the body of the for /F loop we are able to determine whether or not the loop iterated, thus knowing whether the current directory name only consists of decimal digits.

The script writes to and reads from the variable NAME in the same block of code, which can normally not be done, unless you enable delayed variable expansion.

You can use the system environment variable %UserProfile% instead of specifying C:\Users\xxx.xxx, so the script may even work on a system where the user profile directory is not at the default location.

Upvotes: 1

Compo
Compo

Reputation: 38708

You could use FindStr to isolate the directories matching your pattern:

:

@Echo Off
Set "SrcDir=%UserProfile%\Desktop\folder1"
Set "DstDir=%UserProfile%\Desktop\New folder"
For /F Delims^=^ EOL^= %%A In ('
    "Dir /B/AD "%SrcDir%\*" 2>NUL|FindStr "^[0-9][0-9][0-9][0-9][0-9][0-9]$""
')Do XCopy "%SrcDir%\%%A\*.txt" "%DstDir%\" /D:09-09-2019 /Y>NUL 2>&1

Just modify the paths between the = and " on lines 2 and 3 to suit your actual source and destination directories.

Upvotes: 1

Related Questions