I would like to use a batch file to delete all blank lines in multiple files in the directory "Data". I don't want to rename the files.
I have seen this post, but it does not help: How to delete blank lines from multiple files in a directory for the following reasons:
* Files are renamed
* Files must be in same directory as the .bat file
If you could also explain the batch file commands, then that would be greatly appreciated.
Thanks.
I've decided to include all the explanations as comments. There are some ways of doing it without a rename/move operation, but are not as reliable as this. Anyway, at the end, files will have the same name but no empty lines.
#echo off
setlocal enableextensions disabledelayedexpansion
rem There are some problems with references to batch files
rem that are called with quotes. To avoid the problems, a
rem subroutine is used to retrieve the information of
rem current batch file
call :getBatchFileFullPath batch
rem From the full path of the batch file, retrieve the
rem folder where it is stored
for %%a in ("%batch%") do set "folder=%%~dpa"
rem We will use a temporary file to store the valid
rem lines while removing the empty ones.
set "tempFile=%folder%\~%random%%random%%random%"
rem For each file in the batch folder, if the file is
rem not the batch file itself
for %%a in ("%folder%\*") do if /i not "%%~fa"=="%batch%" (
rem Now %%a holds a reference to the file being processed
rem We will use %%~fa to get the full path of file.
rem Use findstr to read the file, and retrieve the
rem lines that
rem /v do not match
rem /r the regular expression
rem /c:"^$" start of line followed by end of line
rem and send the output to the temporary file
findstr /v /r /c:"^$" "%%~fa" > "%tempFile%"
rem Once we have the valid lines into the temporary
rem file, rename the temporary file as the input file
move /y "%tempFile%" "%%~fa" >nul
)
rem End - Leave the batch file before reaching the subroutine
exit /b
rem Subrotutine used to retrieve batch file information.
rem First argument (%1) will be set to the name of a variable
rem that will hold the full path to the current batch file.
:getBatchFileFullPath returnVar
set "%~1=%~f0"
goto :eof
The uncommented version
#echo off
setlocal enableextensions disabledelayedexpansion
call :getBatchFileFullPath batch
for %%a in ("%batch%") do set "folder=%%~dpa"
set "tempFile=%folder%\~%random%%random%%random%"
for %%a in ("%folder%\*") do if /i not "%%~fa"=="%batch%" (
findstr /v /r /c:"^$" "%%~fa" > "%tempFile%"
move /y "%tempFile%" "%%~fa" >nul
)
exit /b
:getBatchFileFullPath returnVar
set "%~1=%~f0"
goto :eof
Related
I have a batch script already working for some months. The purpose of the script is to create a folder based on the file name and rename the folder accordingly for a certain purpose. However, it stops moving the files to the created folder in the loop. I tested it on other machine and it was working fine, but on a particular machine; it is just not working.
What can I do to make the loop effective and why did the batch stop working (moving files to folder) after working for many months now?
setlocal EnableDelayedExpansion
for /F %%a in ('dir "C:\Program Files\WinSCP\Unconverted" /a-d /b') do (
if not "%%~dpnxa"=="%~dpnx0" call :func "%%~a"
:func
set file=%~1
set dir=%file:~0,49%
mkdir "C:\Program Files\WinSCP\Unconverted\%dir%_fdc" 2>nul
rem ECHO "%file%"
rem ECHO "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
move /Y "C:\Program Files\WinSCP\Unconverted\%file%" "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
)
start "" "C:\Program Files\WinSCP\hide_conversion_window.exe"
I rewrote and commented the batch file as it contains several issues whereby most were not problematic as long as this batch file is stored in %ProgramFiles%\WinSCP\Unconverted and this directory is also the current directory on execution of the batch file as on double clicking the batch file.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=%ProgramFiles%\WinSCP\Unconverted"
rem Process all files in source folder found by command DIR with ignoring
rem subfolders and listed in bare format which means only file names with
rem file extension but without file path. The batch file itself is skipped
rem if being also stored in the source folder specified above.
for /F "delims=" %%I in ('dir "%SourceFolder%\*" /A-D /B 2^>nul') do (
if /I not "%SourceFolder%\%%I"=="%~f0" call :MoveFile "%SourceFolder%\%%I"
)
rem Execute converter through AutoIt in a separate command process and
rem while conversion is running continue with batch processing which means
rem restoring previous environment and finally exiting batch file processing.
start "" "%ProgramFiles%\WinSCP\hide_conversion_window.exe"
endlocal
goto :EOF
rem MoveFile is a subroutine which expects to be called with one argument
rem being the name of the file to move with full file name which means
rem with file path, file name and file extension.
rem The first 49 characters of the file name define the name for target
rem folder on which "_fdc" must be appended for completion. This folder
rem is created without verification on success and then the file is
rem moved into this folder again without verification on success.
:MoveFile
set "FileName=%~nx1"
set "FolderName=%FileName:~0,49%_fdc"
mkdir "%~dp1\%FolderName%" 2>nul
move /Y "%~1" "%~dp1\%FolderName%\" >nul
goto :EOF
This batch file works for batch file being stored in a different folder than source folder or current directory is a different directory than the folder containing the batch file or a found file contains a space character or any other special character like &()[]{}^=;!'+,`~.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
mkdir /?
move /?
set /?
setlocal /?
start /?
Read also the Microsoft article about Using Command Redirection Operators.
Thanks for the suggestion oldabi. Sometimes things do work and we are thinking is all perfect until it breaks down. Thanks for the suggestion. I just realised my mistake about missing bracket.
SETLOCAL ENABLEDELAYEDEXPANSION
for /F %%a in ('dir "C:\Program Files\WinSCP\Unconverted" /a-d /b') do (
if not "%%~dpnxa"=="%~dpnx0" call :func "%%~a" )
goto conversion
:conversion
rem ::execute converter through autoit
start "" "C:\Program Files\WinSCP\hide_conversion_window.exe"
:func
set file=%~1
set dir=%file:~0,49%
mkdir "C:\Program Files\WinSCP\Unconverted\%dir%_fdc" 2>nul
rem ECHO "%file%"
rem ECHO "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
MOVE /Y "C:\Program Files\WinSCP\Unconverted\%file%" "C:\Program Files\WinSCP\Unconverted\%dir%_fdc"
I am new to batch Scripting. The requirement is, Directory contains folders with sub folders and files. Need to delete all files except two files, which contains the extension like .css .html. Don't know about batch(.bat) Scripting. Please help me
Thanks in Advance
you could try something like this which will loop through all directories from where the batch file is placed and delete files that don't match the desired extension
#echo off
echo.
REM loop through files
for /r %%f in (*) do call :myFunc %%f
goto End
REM function to check files
:myFunc
set file=%1
set delete=TRUE
REM don't delete the batch script (replace with your batch script name)
if not "%file%"=="%file:batchscriptname.bat=%" set delete=FALSE
REM don't delete .html files
if not "%file%"=="%file:.html=%" set delete=FALSE
REM don't delete .css files
if not "%file%"=="%file:.css=%" set delete=FALSE
REM execute the delete
if "%delete%"=="TRUE" echo %file%
goto :eof
:End
#Echo off
for / "delims=" %%A in (
'dir /B/S/A-d X:\startfolder\* ^|findstr /i /v "\.css$ \.html$" '
) Do echo Del "%%~fA"
If the output looks right, remove the echo in front of del.
My photo import tool (Picasa) does a great job at importing photos and videos from my phone and camera. What I like is that it creates a subfolder under the Pictures directory based on the Photo Taken Date of each photo/video. So you end up with this structure:
C:\Pictures\2017-02-01\DSC_0001.jpg
C:\Pictures\2017-02-01\DSC_0002.jpg
C:\Pictures\2017-02-01\DSC_0003.mp4 <--- problem
The only problem is that it puts videos in this same structure under Pictures.
As such, I'd like to right a batch script to find and move all video files (.mp4, .avi, .mov) from the C:\Pictures directory to the C:\Videos directory, but also with the date subfolder....
i.e.
Move C:\Pictures\2017-02-01\DSC_0003.mp4 to C:\Videos\2017-02-01\DSC_0003.mp4
Note that the date subfolder may or may not exist under C:\Videos.
Also since these are large video files, and there are a lot of them, I'd prefer a process that actually does a move and not a copy then delete, for the sake of speed and disk space utilization as I am almost out of space (after re-organizing these files, I will be archiving off to a NAS).
Also prefer using RoboCopy, xcopy, or xxcopy as I have them and use them today on my machine. If massively easier using PowerShell scripting, I can learn that if it is easy to do.
Final Solution
I used Mofi's answer, but enhanced it just a bit to add a function to calculate the directory string length
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define folder with the pictures which is never deleted.
set "PicturesFolder=D:\Users\Chad\PicturesTest"
rem get string length of source directory to later use in a substring type function
call :strlen PicturesFolderDirectoryLength PicturesFolder
echo PicturesFolderDirectoryLength = %PicturesFolderDirectoryLength%
rem Change the current directory to directory with the pictures.
cd /D "%PicturesFolder%"
rem Search recursive in this directory for video files with
rem file extension AVI, MOV, MP4 or MPG and move those files.
for /F "delims=" %%I in ('dir /A-D /B /S *.avi *.mov *.mp4 *.mpg 2^>nul') do call :MoveVideo "%%I"
rem Discard all environment variables defined in this batch code
rem and restore initial current directory before exiting batch file.
endlocal
goto :EOF
rem MoveVideo is a subroutine called with name of current
rem video file name with full path by the FOR loop above.
rem It first defines target path for video file depending on source path
rem by removing the backslash at end and concatenating C:\Videos with the
rem source path omitting the first 11 characters which is C:\Pictures.
rem Then the target directory structure is created with redirecting the
rem error message output by command MD to handle STDERR in case of the
rem target directory already exists to device NUL to suppress it.
rem Next the video file is moved from source to target folder with silently
rem overwriting an already existing file with same name in target folder
rem because of using option /Y. Remove this option if a video file should
rem be kept in pictures folder and an error message should be displayed in
rem case of a video file with same name already existing in target folder.
rem Last the source folder is removed if it is completely empty which means
rem it does not contain any file or subfolder. All parent folders up to the
rem pictures folder are also removed if each parent folder is also empty
rem after deletion of an empty folder.
rem The subroutine is exited with goto :EOF and execution of batch file
rem continues in main FOR loop above with next found video file.
:MoveVideo
set "SourcePath=%~dp1"
set "SourcePath=%SourcePath:~0,-1%"
ECHO SourcePath=%SourcePath%
CALL SET "SourceSubFolder=%%SourcePath:~%PicturesFolderDirectoryLength%%%"
ECHO SourceSubFolder=%SourceSubFolder%
set "TargetPath=D:\Users\Chad\VideosTest%SourceSubFolder%"
echo TargetPath=%TargetPath%
md "%TargetPath%" 2>nul
move /Y "%~1" "%TargetPath%\%~nx1" >nul
:DeleteSourceFolder
rd "%SourcePath%" 2>nul
if errorlevel 1 goto :EOF
for /F "delims=" %%D in ("%SourcePath%") do set "SourcePath=%%~dpD"
set "SourcePath=%SourcePath:~0,-1%"
if /I not "%SourcePath%" == "%PicturesFolder%" goto DeleteSourceFolder
goto :EOF
:strlen <resultVar> <stringVar>
(
setlocal EnableDelayedExpansion
set "s=!%~2!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "s=!s:~%%P!"
)
)
)
(
endlocal
set "%~1=%len%"
exit /b
)
Here is a commented batch code for this file moving task with keeping directory structure.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define folder with the pictures which is never deleted.
rem Note: ~11 in third line of subroutine MoveVideo must be
rem replaced by ~length of the folder path defined here.
set "PicturesFolder=C:\Pictures"
rem Change the current directory to directory with the pictures.
cd /D "%PicturesFolder%"
rem Search recursive in this directory for video files with
rem file extension AVI, MOV, MP4 or MPG and move those files.
for /F "delims=" %%I in ('dir /A-D /B /S *.avi *.mov *.mp4 *.mpg 2^>nul') do call :MoveVideo "%%I"
rem Discard all environment variables defined in this batch code
rem and restore initial current directory before exiting batch file.
endlocal
goto :EOF
rem MoveVideo is a subroutine called with name of current
rem video file name with full path by the FOR loop above.
rem It first defines target path for video file depending on source path
rem by removing the backslash at end and concatenating C:\Videos with the
rem source path omitting the first 11 characters which is C:\Pictures.
rem Then the target directory structure is created with redirecting the
rem error message output by command MD to handle STDERR in case of the
rem target directory already exists to device NUL to suppress it.
rem Next the video file is moved from source to target folder with silently
rem overwriting an already existing file with same name in target folder
rem because of using option /Y. Remove this option if a video file should
rem be kept in pictures folder and an error message should be displayed in
rem case of a video file with same name already existing in target folder.
rem Last the source folder is removed if it is completely empty which means
rem it does not contain any file or subfolder. All parent folders up to the
rem pictures folder are also removed if each parent folder is also empty
rem after deletion of an empty folder.
rem The subroutine is exited with goto :EOF and execution of batch file
rem continues in main FOR loop above with next found video file.
:MoveVideo
set "SourcePath=%~dp1"
set "SourcePath=%SourcePath:~0,-1%"
set "TargetPath=C:\Videos%SourcePath:~11%"
md "%TargetPath%" 2>nul
move /Y "%~1" "%TargetPath%\%~nx1" >nul
:DeleteSourceFolder
rd "%SourcePath%" 2>nul
if errorlevel 1 goto :EOF
for /F "delims=" %%D in ("%SourcePath%") do set "SourcePath=%%~dpD"
set "SourcePath=%SourcePath:~0,-1%"
if /I not "%SourcePath%" == "%PicturesFolder%" goto DeleteSourceFolder
goto :EOF
This batch file also removes all folders in C:\Pictures which become empty after moving the video files. But it does not remove folders which were already empty on starting the batch file.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
cd /?
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
move /?
rd /?
rem /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of >nul and 2>nul. In the main FOR loop the redirection operator > is escaped with caret character ^ to be interpreted as literal character on parsing FOR command line and later as redirection operator on execution of DIR command line by FOR.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
XCOPY /T "%sourcedir%" "%destdir%"
FOR %%x IN (mp4 mov) DO (
FOR /f "tokens=1*delims=>" %%a IN (
'XCOPY /Y /s /d /F /L "%sourcedir%\*.%%x" "%destdir%"'
) DO IF "%%b" neq "" (
SET "topart=%%b"
SET "frompart=%%a"
ECHO(MOVE /y "!frompart:~0,-2!" "!topart:~1!"
)
)
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances.
The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
The first xcopy creates the required subtrees, the second uses the /L option to list rather than copy the files
The loop on %%x assigns %%x to the required extensions. The output from the inner xcopy will be of the form fullsourcefilename -> fulldestinationfilename so it needs to be parsed using > as a delimiter, from-filename to %%a, to-filename to %%b. If %%b is not set, then this is the final line of xcopy's report (n files copied) which needs to be ignored. The to and from filenames need to be trimmed of unwanted, but fortunately constant character strings.
What is interesting is that there appears to be no way using xcopy to suppress prompting in the case where the destination filename already exists.
I am trying to step through a folder with a batch file. The folder has file names as
1.txt
2.txt
10.txt
100.txt
etc.
So I want to rename them to something like
001.txt
002.txt
010.txt
100.txt
etc.
I have tried
FOR /R C:\Test\ %%G IN (*.txt) DO echo "%%G"
But this gives me an output of
1.txt
10.txt
100.txt
2.txt
How do I get it to output in order?
Here is a commented batch code for this task:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem The environment variable LeadingZeros will be a string containing as
rem much zeros as longest file name has characters without file extension.
set "LeadingZeros="
rem The environment variable ZerosCount will have the number of zeros.
set "ZerosCount=0"
rem Search in current directory for files with extension TXT and call for
rem each file name without file extension the subroutine GetLeadingZeros.
for %%I in (*.txt) do call :GetLeadingZeros "%%~nI"
rem Is there no file with more than 1 character, there
rem is nothing to do and therefore exit this batch file.
if %ZerosCount% LEQ 1 endlocal & goto :EOF
rem Otherwise insert at beginning of each file name the string with
rem the leading zeros and rename the file with using only the last
rem ZerosCount characters from file name with leading zeros.
for %%I in (*.txt) do (
set "FileName=%LeadingZeros%%%~nI"
ren "%%~fI" "!FileName:~-%ZerosCount%!%%~xI"
)
rem Exit the batch file after renaming all files.
endlocal
goto :EOF
rem This subroutine determines length of current file name and at
rem the same time builds a string with just zeros of same length.
rem Once the file name length and number of zeros for this file is
rem determined, this number is compared with the greatest length already
rem determined before. If this file has a longer file name than all other
rem files before, this file name specifies the number of zeros to insert
rem at begin of each file name in the second loop above.
:GetLeadingZeros
set "TempZeros="
set "TempCount=0"
set "FileName=%~1"
:NextChar
if "%FileName%" == "" goto CompareLengths
set "TempZeros=%TempZeros%0"
set "FileName=%FileName:~1%"
set /A TempCount+=1
goto NextChar
:CompareLengths
if %TempCount% LEQ %ZerosCount% goto :EOF
set "LeadingZeros=%TempZeros%"
set "ZerosCount=%TempCount%"
goto :EOF
It is more complex than really necessary if number of digits is fixed. But coding a batch file for a fixed number of digits of 3 was not really interesting for me as being too simple, look this FOR loop.
#echo off
for %%I in (*.txt) do (
set "FileName=00%%~nI"
ren "%%~fI" "!FileName:~-3!%%~xI"
)
The first batch code finds out longest file name in current directory and determines based on this file name the number of leading zeros to insert at beginning of each file name to get finally all files with same file name length.
EDIT: This batch code is a bit faster than first one, but does the same:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem The environment variable ZerosCount will have the number of zeros
rem which is equal the number of characters of longest file name.
set "ZerosCount=0"
rem Search in current directory for files with extension TXT and call for
rem each file name without file extension the subroutine GetLeadingZeros.
for %%I in (*.txt) do call :GetLeadingZeros "%%~nI"
rem Is there no file with more than 1 character, there
rem is nothing to do and therefore exit this batch file.
if %ZerosCount% LEQ 1 endlocal & goto :EOF
rem The environment variable LeadingZeros will be a string containing as
rem much zeros as longest file name has characters without file extension.
set "LeadingZeros="
for /L %%N in (1,1,%ZerosCount%) do set "LeadingZeros=!LeadingZeros!0"
rem Otherwise insert at beginning of each file name the string with
rem the leading zeros and rename the file with using only the last
rem ZerosCount characters from file name with leading zeros.
for %%I in (*.txt) do (
set "FileName=%LeadingZeros%%%~nI"
echo ren "%%~fI" "!FileName:~-%ZerosCount%!%%~xI"
)
rem Exit the batch file after renaming all files.
endlocal
goto :EOF
rem This subroutine determines length of current file name.
rem Once the file name length is determined, this number is compared with the
rem greatest length already determined before. If this file has a longer file
rem name than all other files before, this file name specifies the number of
rem zeros to insert at begin of each file name in the third loop above.
:GetLeadingZeros
set "NameLength=0"
set "FileName=%~1"
:NextChar
if "%FileName%" == "" goto CompareLengths
set "FileName=%FileName:~1%"
set /A NameLength+=1
goto NextChar
:CompareLengths
if %NameLength% LEQ %ZerosCount% goto :EOF
set "ZerosCount=%NameLength%"
goto :EOF
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
rem /?
ren /?
set /?
setlocal /?
PS: I have never written for myself a batch file for renaming files as I use Total Commander with its built-in multi-rename tool making file/folder renames always a very simple task with no need of coding skills.
A robust solution should have the following features:
Only .txt files with a base name that is purely numeric should be renamed
If the base name length already exceeds your desired width, then it should be ignored (not truncated)
The following solutions meet the above criteria. I chose to pad to 3 digits. It should be a straight forward exercise to expand the width
Pure Batch
#echo off
setlocal enableDelayedExpansion
for /f "delims=" %%F in (
'dir /b /a-d *.txt^|findstr /i "^[0-9][0-9]*\.txt$"'
) do (
set "old=%%F"
set "new=00%%F"
if !old!==!old:~-6! echo ren !old! !new:~-7!
)
JREN.BAT - Hybrid JScript/batch renaming utility
JREREN.BAT is a generic regular expression renaming utility. It is pure script that runs natively on any Windows machine from XP onward. Full documentation is available by running jren /?, or jren /?? if you want paged help.
jren "^\d+\.txt$" "lpad($0,'0000000')" /i /j
Remember that JREN is a batch script, so you must use call jren if you put the command within another batch script.
I try to write a script that can monitor a folder H:\Start and copy a new subfolder with its files in H:\Start to new location H:\Target. The script should store the copied folder and files in a text file.
Each time the script starts new and monitors H:\Start, it should check the text file and copy only those subfolders which are not yet included in the text file because copied already before.
I was searching the world wide web for examples, but could not really find a starting point. Any help would be nice.
I have so far not working good :)
#echo off
setlocal EnableDelayedExpansion
pushd %1
for /D %%d in (“H:\Start\*.*”) do set n=!n!;%%d
if defined n echo %n:~1% > C:\Desktop\list.txt
popd
endlocal
for /f %%i in (C:\Desktop\list.txt) do not (
xcopy /d /s H:\Start H:\Target > C:\Desktop\list.txt >nul 2>&1
)
I suggest using:
%SystemRoot%\System32\xcopy.exe H:\Start H:\Target /C /H /I /K /M /Q /R /S /Y >nul
For information about all those parameters of xcopy open a command prompt window and run there xcopy /? to get help of this command displayed which explains all those parameters.
The important one is /M which selects for copying process just files with archive attribute set and which removes the archive attribute on each file in H:\Start after copying the file. This avoids that a once copied file is copied once more as long as not modified in H:\Start since last copy.
If you want to log all copied files into a text file, I suggest using:
%SystemRoot%\System32\xcopy.exe H:\Start H:\Target /C /F /H /I /K /M /R /S /Y >>C:\Desktop\list.txt
The names of the copied files are with this command line appended to text file C:\Desktop\list.txt
The following commented batch code works with directory lists as asked for.
#echo off
rem Define source and destination directory as well as
rem the names of the used list files each with full path.
setlocal EnableExtensions
set "Source=H:\Start"
set "Destination=H:\Target"
set "MainDirList=C:\Desktop\list.txt"
set "CurrentList=%Temp%\CurrentList.tmp"
set "ExcludeList=%Temp%\ExcludeList.tmp"
set "FinalDoList=%Temp%\FinalDoList.tmp"
rem Write the names of all subdirectories found in source
rem directory into a list file in directory for temporary files.
dir /AD /B "%Source%">"%CurrentList%"
rem Check if list file is not empty because of no subdirectories.
call :CheckEmpty "%CurrentList%"
if %FileIsEmpty% == 1 (
echo No directories in %Source%
goto EndBatch
)
rem Start copying the directories if there is no main list file
rem from a previous execution of this batch file or the main list
rem file was deleted intentionally to force copying all again.
if not exist "%MainDirList%" goto CopyDirectories
rem Start copying also if main list file is an empty file.
call :CheckEmpty "%MainDirList%"
if %FileIsEmpty% == 1 del "%MainDirList%" & goto CopyDirectories
rem Search in main list for lines matching completely lines in current
rem list with ignoring case and write the found lines into an exclude
rem list file as those directories were copied already before.
%SystemRoot%\System32\findstr.exe /I /L /X /G:"%CurrentList%" "%MainDirList%" >"%ExcludeList%"
rem Copy all directories if no line in current list is found in main list.
if errorlevel 1 goto CopyDirectories
rem Get all lines from current list not listed also in exclude list.
%SystemRoot%\System32\findstr.exe /B /I /L /V /G:"%ExcludeList%" "%CurrentList%" >"%FinalDoList%"
rem Replace the current list with the reduced final list.
move /Y "%FinalDoList%" "%CurrentList%"
rem Check if remaining current list is not empty because
rem all subdirectories copied already before.
call :CheckEmpty "%CurrentList%"
if %FileIsEmpty% == 1 (
echo Copied already before all directories in %Source%
goto EndBatch
)
:CopyDirectories
rem Copy each directory in remaining current list file.
for /F "usebackq delims=" %%D in ("%CurrentList%") do (
echo Coping %Source%\%%D
%SystemRoot%\System32\xcopy.exe "%Source%\%%D" "%Destination%\%%D" /C /H /I /K /Q /R /S /Y >nul
)
rem Append the list of copied directories to main list file.
type "%CurrentList%">>"%MainDirList%"
goto EndBatch
:CheckEmpty
rem This little subroutine just checks if size of a list file is 0.
if %~z1 == 0 ( set "FileIsEmpty=1" ) else ( set "FileIsEmpty=0" )
goto:EOF
:EndBatch
rem Delete all not further needed listed files and environment variables.
del "%ExcludeList%" 2>nul
del "%CurrentList%"
endlocal
This batch file should work for the FTP folder mounted as drive on Windows. It does not depend on attributes or timestamps. It uses explicitly only the names of the directories in H:\Start. It also does not check which directories exist already in H:\Target. Therefore it is possible to delete a directory in H:\Target if not interested in and the deleted directory will be nevertheless not copied once again from H:\Start as long as the deleted directory is not also removed from main list file.
For details on parameters used on findstr run in a command prompt window findstr /? and read the entire help output into the window.
Thanks for this question as this was really an interesting batch coding task.
You don't need to store anything, you can use
xcopy /d /s h:\start h:\target
/D:mm-dd-yyyy
Copy files changed on or after the specified date.
If no date is given, copy only files whose
source date/time is newer than the destination time.
but if you need a list of the files you can just use a redirection :
xcopy /d /s h:\start h:\target > logfile.txt