Reputation: 3
I'm trying to copy specific files from C:
to "X:
for example". The files are named with the same format.
A1234_ZZabc123_DT1_F1.tst
A4567_ZZdef4567_DT2_F2.tst
A8901_ZZghi1289_DT1.tst
A2345_ZZjfkbu12_to_modify.tst
A6789_ZZlmny568_F1_to_modify.tst
A1234_ZZabc478_DT1.txt
I want to copy only the .tst
files, and with the same format as the first 3 Axxxx_ZZyyyxxx_DTx_Fx.tst
where x
=number and y
=letter.
After ZZ, it might be 4 letters and 3 numbers, or 5 letters and 4 numbers, like a "namecode".
Example: ZZkusha122
or ZZkus1551
.
I need to copy the folders along with the files too.
I'm new to coding and really need some help.
I need to find and copy all those files along 10k+ files together
Upvotes: 0
Views: 181
Reputation: 80033
You claim that the first 3 of your example filenames fit the pattern you describe. I believe that only two do.
@ECHO OFF
SETLOCAL
rem The following setting for the directory is a name
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
FOR /f "delims=" %%e IN (
'dir /b /a-d "%sourcedir%\A*.tst"^|findstr /X /I /R "A[0-9][0-9][0-9][0-9]_ZZ[a-z][a-z][a-z]_DT[0-9]_F[0-9].tst" '
) DO ECHO COPY "%sourcedir%\%%e" X:
)
GOTO :EOF
Always verify against a test directory before applying to real data.
The required COPY commands are merely ECHO
ed for testing purposes. After you've verified that the commands are correct, change ECHO COPY
to COPY
to actually copy the files. Append >nul
to suppress report messages (eg. 1 file copied
)
Simply execute a dir
command that reports only filenames matching the *.tst
mask. Filter this list with findstr
which /X
exactly matches the regular expression provided. findstr
only has a limited implementation of regular expressions. The /I
forces a case-insensitive match. If you want case-sensitive, remove the /I
and change each [a-z]
to [a-zA-Z]
(leave as-is if you want lower-case only in these positions.)
See findstr /?
from the prompt for more documentation, or search for examples on SO.
---- revision to cater for multiple filemasks and subdirectories ---
@ECHO OFF
SETLOCAL
rem The following setting for the directory is a name
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "maskfile=%sourcedir%\q74442552.txt"
FOR /f "tokens=1*delims=" %%e IN (
'dir /b/s /a-d "%sourcedir%\*.tst"^|findstr /E /I /R /g:"%maskfile%" '
) DO ECHO COPY "%%e" X:
)
GOTO :EOF
Changes:
maskfile
dir
command requires the /s
switch to scan subdirectoriesdir
command loses the initial A
findstr
command replaces the /X
switch with /E
findstr
command loses the regex expression. These are transferred to a file and the file is nominated by the /g:
switch.copy
command loses the source-directory as the directory will be included in %%e
The file "q74442552.txt" contains lines that are of the form
A[0-9][0-9][0-9][0-9]_ZZ[a-z][a-z][a-z]_DT[0-9]_F[0-9].tst
A[0-9][0-9][0-9][0-9]_ZZ[a-z][a-z][a-z]_to.*.tst
This time, %%e
acquires the full pathname of the files found. Since the filemask ends .tst
, the only filenames to pass the dir
filter will be those that end .tst
.
The /e
switch tells findstr
to match string that End with the regex strings in the file specified as /g:
.
The strings in the file must comply with Microsoft's partial regex
implementation, one to a line.
In summary, findstr
uses as regex
\
to use it literallylow-high
So - you then need to brew-your own using the examples I've supplied. The second line matches Axxxx_ZZyyy_to{anything}.tst
for instance.
--- Minor revision to deal with maintaining destination-tree ----- (see notes to final revision for why this doesn't quite work)
@ECHO OFF
SETLOCAL
rem The following setting for the directory is a name
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "maskfile=%sourcedir%\q74442552.txt"
SET "destdir=u:\your results"
FOR /f "tokens=1*delims=" %%e IN (
'dir /b/s /a-d "%sourcedir%\*.tst"^|findstr /E /I /R /g:"%maskfile%" '
) DO ECHO "%%~nxe"&XCOPY /Y /D /S "%sourcedir%\%%~nxe" "%destdir%\">nul
)
GOTO :EOF
This version adds the destination root directory as destdir
.
The dir ... findstr...
works as before to list the filenames to copy.
The prior version used echo copy
to report the proposed copy operation, but the destination was always the same directory.
The replacement XCOPY
line maintains the directory structure at the destination.
Note : the XCOPY
is "live". The files will be copied to the destination if run as-is. Always verify against a test directory before applying to real data.
To "defuse" the XCOPY
, add the /L
switch and remove the >nul
. This will cause XCOPY
to report the source name that would be copied instead of copying
it. (The >nul
suppresses the report)
The /D
only copies source files that eitherr do not exist in the destination of have a later datestamp in the source.
The action is to xcopy
each filename found (%%~nxe
) from the source directory tree to the destination. Therefore, any file xyz.tst
found anywhere in the source tree will be xcopy
d to the destination tree. The /D
means that once xyz.tst
is encountered on the source tree, it will be skipped should it be encountered again.
--- Final (I hope) revision ---
@ECHO OFF
SETLOCAL
rem The following setting for the directory is a name
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=U:\Users\tocil\Desktop\aoi"
SET "maskfile=%sourcedir%\q74442552.txt"
SET "destdir=u:\your results"
FOR /f "tokens=1*delims=" %%e IN (
'dir /b/s /a-d "%sourcedir%\*.tst"^|findstr /E /I /R /g:"%maskfile%" '
) DO (
rem drive and path to 'dirname' - has terminal "\"
SET "dirname=%%~dpe"
rem remove the sourcedir from dirname
FOR %%y IN ("%sourcedir%") DO CALL SET "dirname=%%dirname:%%~y=%%"
rem copy or xcopy the file to the destination.
FOR /f "tokens=2delims==" %%y IN ('set dirname') DO XCOPY /Y "%%e" "%destdir%%%y">nul
)
)
GOTO :EOF
Always verify against a test directory before applying to real data.
Note to self: Only if the filemask provided to XCOPY
is ambiguous (ie. contains ?
or *
) will XCOPY obey the /s
switch unless the target file exists in the starting source directory.
hence
xcopy /s sourcedir\myfile destdir
will copy myfile
from the entire tree ONLY if sourcedir\myfile
exists.
xcopy /s sourcedir\myf?le destdir
will copy myfile
from the entire tree regardless. Unfortunately it will also copy myfale
and myfule
as well.
Hence, the new approach.
First, perform a dir /b /s
to get all of the filenames and filter as before. This is being assigned to %%e
.
Take the drive and path only of the file and assign to dirname
.
The next step is a little complex. First, set the value of %%y
to the name of the source directory. Next, use a parser trick to remove that name from dirname
. The mechanics are: Parse the %%dirname:%%~y=%%
(because the call
causes the set
to be executed in a sub-shell) whuch does the normal left-to-right evaluation. %%
is an escaped-%, so is replaced by %
; %%y
is an active metavariable so is replaced by (the name of the source directory) and the ~
causes the quotes to be stripped from that name. The resultant command executed is thus SET "dirname=%dirname:nameofsourcedirectory=%"
So now we can construct a copy
-class instruction. dirname
now contains the relative directory for the destination, which we can extract from the environment by parsing a set
listing (Could also be done with delayed expansion
) where %%y
gets set to the relative directory and has both a leading and trailing backslash, so the destination directory is simply "%destdir%%%y"
. XCOPY
then knows to create that directory if necessary (%%y
has a trailing backslash) and we know the source filename is in %%e
.
You could also use a copy
to do the same thing, but you'd need to create the destination directory first. Another advantage of XCOPY
is that you can also specify the /d
switch to not copy files that have an earlier date over files that have a later date.
Upvotes: 1