Batch File - Recursively check folders and move files - batch-file

I am trying to create a windows batch file that will scan a folder with many sub folders. Each sub folder can contain many files. I need the script to check if a sub folder contains over a certain number of files, and if it does move half of the files to a new folder with the same name but with a number at the end.
Example:
Main folder
-Subfolderone
-Subfoldertwo
-Subfolderthree
If Subfoldertwo contains over a certain number of files, lets say 1000, then half of the files within Subfoldertwo will be moved to Subfoldertwo(2), and so on for each sub folder.
Main folder
-Subfolderone
-Subfoldertwo
-Subfoldertwo(2)
-Subfolderthree
Any help would be much appreciated. Thank you.

#ECHO OFF
SETLOCAL
SET "sourcedir=c:\sourcedir"
SET limit=5
FOR /f "delims=" %%a IN ('dir /b /s /ad "%sourcedir%\*"') DO (
SET /a newnum=2
FOR /f %%c IN ('dir /b/a-d "%%~a" 2^>nul ^|find /c /v ""') DO IF %%c gtr %limit% CALL :process "%%a"
)
)
GOTO :EOF
:process
IF EXIST "%~1(%newnum%)\" SET /a newnum+=1&GOTO process
ECHO MD "%~1(%newnum%)"
FOR /f "skip=%limit%delims=" %%m IN ('dir /b /a-d "%~1"') DO ECHO MOVE "%~1\%%m" "%~1(%newnum%)\"
GOTO :eof
Simple enough. I've set the sourcedir to a constant for my testing and the limit to 5 for the same reason.
First build a list of the original diretory tree, then count the files in each directory. If that count is greater than the limit, process the directory.
In process, first find whether the proposed new directory already exists. If it does, keep incrementing the number 'til it doesn't.
Then list the filenames (only) from the original full-directoryname, skipping the first %limit% and for the remainder, move them to the new directoryname.
The required commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO MD to MD to actually create the directories. Append 2>nul to suppress error messages (eg. when the directory already exists)
AND change ECHO MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
Edit : revised for 'move half the files'
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\sourcedir"
SET limit=5
FOR /f "delims=" %%a IN ('dir /b /s /ad "%sourcedir%\*"') DO (
SET /a newnum=2
FOR /f %%c IN ('dir /b/a-d "%%~a" 2^>nul ^|find /c /v ""') DO IF %%c gtr %limit% SET /a nmove=%%c / 2&CALL :process "%%a"
)
)
GOTO :EOF
:process
IF EXIST "%~1(%newnum%)\" SET /a newnum+=1&GOTO process
ECHO MD "%~1(%newnum%)"
FOR /f "skip=%nmove%delims=" %%m IN ('dir /b /a-d "%~1"') DO ECHO MOVE "%~1\%%m" "%~1(%newnum%)\"
GOTO :eof
(simply calculate half of the count into nmove then skip that number instead)

you might test this:
#ECHO OFF &SETLOCAL
set "StartFolder=X:\Main folder"
set /a MaxFiles=1000
cd /d "%StartFolder%"
:NewFolderCreated
set "NewFolderFlag="
for /f "delims=" %%a in ('dir /b /ad /on') do call:process "%StartFolder%\%%~a"
if defined NewFolderFlag (goto:NewFolderCreated) else goto:eof
:process
SETLOCAL
cd "%~1"
for /f %%b in ('dir /b /a-d 2^>nul^|find /c /v ""') do set /a FileCount=%%b
if %FileCount% leq %MaxFiles% exit /b
set /a MoveCount=FileCount-MaxFiles
set "CurrentFolder=%~n1"
set "NextPath=%StartFolder%\%CurrentFolder%(2)%~X1"
echo("%CurrentFolder%"|findstr /re ".*([0-9][0-9]*)\"^">nul||goto:moving
set "BasePath=%CurrentFolder:~0,-1%"
:loop
if not "%BasePath:~-1%"=="(" set "FolderNo=%BasePath:~-1%%FolderNo%"&set "BasePath=%BasePath:~0,-1%"&goto:loop
set /a FolderNo+=1
set "NextPath=%StartFolder%\%BasePath%%FolderNo%)%~X1"
:moving
echo(Moving %MoveCount% files from "%~1" to "%NextPath%".
md "%NextPath%" 2>nul &&set "NewFolderFlag=true"
for /f "skip=%MaxFiles%delims=" %%b in ('dir /b /a-d /o-n') do move "%~1\%%~b" "%NextPath%" >nul
endlocal &set "NewFolderFlag=%NewFolderFlag%"
exit /b

Related

Batch script to check if number of files in folder is less X and then execute command

So I have a folder that processes the containing files automatically.
I have another folder that has thousands of files to be processed and I created a script that moves 100 files to that processing folder every hour with Task Scheduler, but I want to do it only if that destination folder has less than 20 files in it.
Can someone help me?
Thanks
#echo off
set Source=Source folder
set Target=Destination folder
set MaxLimit=100
for /f "tokens=1* delims=[]" %%G in ('dir /A-D /B "%Source%\*.*" ^| find /v /n ""') do (
move /y "%Source%\%%~nxH" "%Target%"
if %%G==%MaxLimit% exit /b 0
)
Do a simple count on files in the destination folder to determine if processing should occur using a condition check.
Set "Target=Destination folder"
Set count=0
FOR %%a IN (%Target%\*.*) DO (
Set /a count+=1
)
If %count% LSS 20 (
GOTO process
) else (
EXIT
)
:process
"Insert your Move command Here"
Count the files in the target location and exit if there are enough
#echo off
set Source=Source folder
set Target=Destination folder
set MaxLimit=100
for /f %%a in ('dir /b /a-d "%target%\*" ^|find /c /v ""') do set "remaining=%%a"
if %remaining% geq 20 (
echo enough files in target; nothing to do.
goto :eof
)
for /f "tokens=1* delims=[]" %%G in ('dir /A-D /B "%Source%\*.*" ^| find /v /n ""') do (
move /y "%Source%\%%~nxH" "%Target%"
if %%G==%MaxLimit% exit /b 0
)
Or count the files in the destination folder and only process if there are less than your defined quantity:
#Set "SrcDir=Source folder"
#Set "DstDir=Destination folder"
#Set /A "MaxCnt=100,MinCnt=20"
#For /F %%A In ('""%__AppDir__%xcopy.exe" "%DstDir%\*" ? /LSHQ 2>NUL"'
)Do #If %%A Lss %MinCnt% For /F "Tokens=1*Delims=[]" %%B In (
'"Dir /B/A-D/O-D "%SrcDir%"|"%__AppDir__%find.exe" /V /N """'
)Do #Move /Y "%SrcDir%\%%~nxC" "%DstDir%">NUL&If %%B Equ %MaxCnt% Exit /B 0

Opening a random folder from a set directory

How can I create a batch script that opens a random folder within a specific directory? This code here prints out a randomly chosen file(I need it to open the folder, not the file) but I could not figure out how to open it.
#Echo Off
:Start
set directory="D:\Movies"
set count=0
for /f %%f in ('dir "%directory%" /b /s') do set /a count+=1
set /a randN=%random% %% %count% +1
set listN=0
for /f "tokens=1* delims=:" %%I in ('dir "%directory%" /a-d /b /s^| findstr /n /r . ^| findstr /b "%randN%"') do set filename=%%J
:Found
echo %filename%
pause
goto Start
I suddenly realised what I was doing wrong and solved the problem. Here is the final and working code:
#Echo Off
:Start
set directory="D:\Film"
set count=0
for /f %%f in ('dir "%directory%" /ad /b /s') do set /a count+=1
set /a randN=%random% %% %count% +1
set listN=0
for /f "tokens=1* delims=:" %%I in ('dir "%directory%" /ad /b /s^| findstr /n /r . ^| findstr /b "%randN%"') do set filename=%%J
:Found
%SystemRoot%\explorer.exe %filename%
exit /b
goto Start
You really shouldn't need to increment a count and use findstr for such a task; just assigning and sorting a random number should do:
#Echo Off
Set "source=D:\Film"
SetLocal EnableDelayedExpansion
For /D %%A In ("%source%\*") Do Set "$[!RANDOM!]=%%A"
For /F "Tokens=1* Delims==" %%A In ('"Set $[ 2>Nul|Sort"'
) Do Set "target=%%B" & GoTo Found
Exit /B
:Found
Explorer "%target%"
If you wanted a recursive directory search then change line 5 to:
For /D /R "%source%" %%A In (*) Do Set "$[!RANDOM!]=%%A"

How to get the difference between documents

Everyday, a document is created automatically named articles.txt.
I have to make several changes to the document.
After the changes made the document is named articles_Final + date.txt
As example : articles_Final_2016_01_07.txt
The documents are then moved to a directory ". \ HISTO \ FINAL".
I have to compare the two last document created and to write the difference in a new document result.txt
I show you my code for findind the two last documents
#echo off & cls
SETLOCAL EnableDelayedExpansion
set "Dossier=.\HISTO\Final"
set /a "n=0, limit=2"
for /F "delims=" %%a in ('dir /B /A-D /O-D /T:W "%Dossier%\*.*"') do (
echo "%%a"
2>nul set /a "n+=1, 1/(limit-n)"||goto :break
)
:break
pause
exit
And le code who compare the two document
Here, I write the name of them but i would like to find the way to write automaticly the result of my first code
findstr /v /g:articles_Final_2016_01_04.txt articles_Final_2016_02_04.txt >result.txt
#echo off
cls
SETLOCAL EnableDelayedExpansion
set "Dossier=.\HISTO\Final"
set /a "n=0, limit=2"
for /F "delims=" %%a in ('dir /B /A-D /O-D /T:W "%Dossier%\*.*"') do (
echo "%%a"
set "file[!n!]=%%a"
2>nul set /a "n+=1, 1/(limit-n)"||goto :break
)
:break
set file
echo findstr /v /g:%Dossier%\%file[0]% %Dossier%\%file[1]%
pause
exit
(untried)
The findstr command will just be echoed - you'd need to check it and redirect the output.
the set file command is simply a way of displaying all variables that start with file.
Here, the final solution
#echo off
cls
SETLOCAL EnableDelayedExpansion
set "Dossier=.\HISTO\FINAL"
set /a "n=0, limit=2"
for /F "delims=" %%a in ('dir /B /A-D /O-D /T:W "%Dossier%\*.*"') do (
echo "%%a"
set "file[!n!]=%%a"
2>nul set /a "n+=1, 1/(limit-n)"||goto :break
)
:break
set file
findstr /v /g:%Dossier%\%file[0]% %Dossier%\%file[1]% >>difference.txt
::fc /L %Dossier%\%file[0]% %Dossier%\%file[1]% >>difference.txt
pause
exit

Command line counter not incrementing

Hi I have a batch script to move x amount of files from one folder to another. The counter that count the files moved is not incrementing. The script is as follows
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
echo on
set DataMax=50
set Counter=1
set SrcMax=50
set DataLoc=Destination Folder
Set HoldLoc=Source Folder
set count=0
FOR /F %%a in ('DIR /B %DataLoc%\*.pst') do set /A count=count+1
if %count% GEQ %DataMax% (Goto Exit) else (GOTO FMove)
:FMove
Echo Gather Top 50 files
FOR /F "TOKENS=*" %%a IN ('dir /A-D /O-D /B %HoldLoc%\*.pst') DO (
if %Counter% LEQ %SrcMax% (
MOVE /y %HoldLoc%\%%a %DataLoc%\
SET /A Counter += 1
)
)
goto Exit
:Exit
exit
The Set /A Counter += 1 does not seem to work. Thanks in Advance for any assistance.
As you already have enabled delayed expansion try like:
FOR /F "TOKENS=*" %%a IN ('dir /A-D /O-D /B %HoldLoc%\*.pst') DO (
if !Counter! LEQ %SrcMax% (
MOVE /y %HoldLoc%\%%a %DataLoc%\
SET /A Counter=Counter+1
)
)
npockmaka has shown how to get your code to work under normal circumstances by using delayed expansion. However, it will fail if any files names contain the ! character (unlikely, but it could happen)
It is possible to make the code work without delayed expansion by intentionally dividing by zero when the maximum count is exceeded. The error message is hidden by redirecting to nul, and the || operator detects the error and conditionally executes the EXIT command.
I also streamlined the first loop to use FIND to quickly get the count, instead of iterating each file.
#echo off
setlocal
set /a count=0, SrcMax=DataMax=50
set "DataLoc=Destination Folder"
set "HoldLoc=Source Folder"
for /f %%N in (
'dir /b "%DataLoc%\*.pst"^|find /c /v ""'
) do if %%N geq %DataMax% exit /b
echo Gather Top 50 files
for /f "eol=: delims=" %%A in (
'dir /a-d /o-d /b "%HoldLoc%\*.pst"'
) do (
set /a "1/(SrcMax-count), count+=1" 2>nul || exit /b
move /y "%HoldLoc%\%%B" "%DataLoc%\"
)
Another option is to number each file via FINDSTR /N, and let FOR /F parse out the number and file name.
#echo off
setlocal
set /a SrcMax=DataMax=50
set "DataLoc=Destination Folder"
set "HoldLoc=Source Folder"
for /f %%N in (
'dir /b "%DataLoc%\*.pst"^|find /c /v ""'
) do if %%N geq %DataMax% exit /b
echo Gather Top 50 files
for /f "tokens=1* delims=:" %%A in (
'dir /a-d /o-d /b "%HoldLoc%\*.pst"^|findstr /n "^"'
) do (
if %%A gtr %SrcMax% exit /b
move /y "%HoldLoc%\%%B" "%DataLoc%"
)
There is one thing that concerns me in your logic.
If you already have 50 files in your destination, then you exit without doing anything. If you do not yet have 50 files, then you move up to 50 files from the source to the destination. If there are 49 files in the destination at the start, then there is the potential to end up with 99 files in the destination, assuming none of the moved file names match the existing files in the destination.

Batch file for counting the files with same initial name and moving them

Is it possible to do this?
In a folder i have files with same initial names
Example:
Main folder
-Quest2323231.txt
Quest2343434.txt
Quest2343435.txt
Fund103.txt
Fund102.txt
I have a config file (abc.config) in which i have name of file on which i need to count and move them . If the count is more than 2 then i need to move them.
In this case for e g I need to find files which have name as 'Quest'
Appreciate you help on this.
#echo off
setlocal enableextensions
set "number="
for /f "tokens=1" %%a in (
'dir /a-d /-c "c:\mainfolder\quest*" 2^>nul^|findstr /b /c:" "'
) do if not defined number set "number=%%a"
if not defined number set "number=0"
echo %number%
Untested: This expects text in the first line of abc.config which is the file information such as Quest in the example and if there are more than 2 matching files in the source folder then it will echo a move command to move them to the target folder.
Change *%file%* to %file%* in two places if you want to match only the start of the filename.
Remove the echo to actually perform the move commands.
#echo off
set "source=c:\mainfolder"
set "target=d:\target\folder"
set /p "file=" < "abc.config"
for /f %%a in ('dir /b /a-d "%source%\*%file%*" ^|find /i "%file%" 2^>nul^|find /c /v "" ') do set "number=%%a"
if %number% GTR 2 for /f "delims=" %%a in ('dir /b /a-d "%source%\*%file%*" ^|find /i "%file%" ') do (
echo move "%source%\%%a" "%target%"
)
pause

Resources