Command line counter not incrementing - batch-file

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.

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

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

Batch File - Recursively check folders and move files

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

Batch Script to Delete Files with Unique Root Stem in Directory

Is it possible to write a batch file that deletes all files in a directory for which the first n characters of the file's root name do not match the first n characters of any other filenames in that directory? For instance, suppose the directory contains the following:
Purcell_HenryA.txt
Purcell_HenryB.txt
Casaubon_IsaacA.txt
In this case, we would want to delete all files in the directory whose first 13 characters did not match the first 13 characters in any other files in the directory. (That is, we'd want to delete only Casaubon_IsaacA.txt.) I have tracked down scripts that delete all files with unique extensions in a directory, but don't know how to begin to write this script, and would therefore be grateful for any leads on the question.
This checks for root filenames of 14 characters and over - and if there is only 1 file with the same leading 13 characters then it will echo del. Remove the echo to make it perform the deletion.
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('dir /b /a-d') do (
set "part=%%~na"
if not "!part:~13,1!"=="" (
set "part=!part:~0,13!"
for /f "delims=" %%b in ('dir /b /a-d "!part!*.*" ^|find /c "!part!" ') do (
if %%b EQU 1 echo del "%%a"
)
)
)
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET target=u:\testdir
DIR /b /a-d %target%
echo====^^ names IN DIR ^^===
SET length=13
SET match=:
SET "candidate="
FOR /f "delims=" %%i IN ('dir /b/a-d "%target%\*"') DO (
SET filename=%%i
SET section=!filename:~0,%length%!
IF !section!==!match! (SET "candidate=") ELSE (
IF DEFINED candidate ECHO(DEL %target%\!candidate!
SET candidate=%%i
SET match=!section!
)
)
IF DEFINED candidate ECHO(DEL %target%\!candidate!
GOTO :EOF
Test result:
abc123_uniquename.txt
another_uniquename.txt
duplicate_name1234.txt
duplicate_name1235.txt
duplicate_name1236.txt
hello.txt
repeated__name1236.txt
repeated__name1235.txt
unique__name1235.txt
===^ names IN DIR ^===
DEL u:\testdir\abc123_uniquename.txt
DEL u:\testdir\another_uniquename.txt
DEL u:\testdir\hello.txt
DEL u:\testdir\unique__name1235.txt
If you are happy after testing, remove both ECHO( to activate the delete function.
For this code file name = name+extension:
#echo off &SETLOCAL enabledelayedexpansion
FOR %%a IN (*) DO (
SET "search=%%~a"
IF "!search:~13!" neq "" (
FOR /f "delims=[]" %%b IN ('dir /b /a-d /on "!search:~0,13!*" ^| find /n "!search:~0,13!"') DO SET found=%%b
IF !found! equ 1 ECHO DEL "%%~a"
)
)
And because I coose a very similar solution as foxidrive here is another one:
#echo off &SETLOCAL enabledelayedexpansion
FOR %%a IN (*) DO (
SET search=%%a
IF "!search:~13!" neq "" SET /a $!search:~0,13!+=1 2>nul
)
FOR /f "tokens=1*delims=$=" %%a IN ('set "$"') DO if %%b equ 1 echo del "%%~a*"
The way i'd go about this is as follows, i will explain the logic and i'll leave you to do the coding.
You will parse all the file names into variables, while increasing each time.
Then you will set a limit to the number of loops to go through. Then you will search the first 13 characters of the file name and if the number of lines is equal to 1 then delete it. After you will increase the variable by 1 and go through the loop, at the end of each loop it will check if it has reached the limit aka the number of files in the directory, if it has reached the limit, end the loop, otherwise continue.
hah, i finally decided to do it after a guy decided to use my idea i described into actual code, anyway this is way shorter and a lot faster than his, tested+verified to work:
#echo off & setlocal enabledelayedexpansion
set dir=directoryyouwanttosearchin
for /f "delims=" %%a in ('dir /A:a /b %dir%') do set /A name+=1 & set file!name!=%%a
:LOOP
set /A cnt+=1
for /f "delims=" %%a in ('dir /A:a /b %dir% ^| find /C /I "!file%cnt%:~0,13!"') do set lines=%%a
if %lines%==1 del %dir%\!file%cnt%! > nul
if %cnt% NEQ %name% Goto :LOOP
exit /b
That's 9 lines :).

Windows Batch file to move X number of files from folder to folder

I'm trying to use a batch file to move files in blocks of 30 if there are less than 20 files in %DataLoc%. I modified code from a prior question. The problem is in the FMove section of the file. No matter what I put in the for line, it gives me an error.
I want this to have the %HoldLoc% value, but have been hard coding it because of errors I get.
The environment is Windows 2008 R2 server.
Variations I have tried, as well as with and without quotes in the parentheses:
FOR %F IN (%HoldLoc%)
FOR %F IN (%%HoldLock%)
FOR %F IN (c:\Play\hold\*.tmp)
My Code:
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
echo on
set DataMax=20
set DataLoc=C:\Play\Data
Set HoldLoc=C:\Play\Hold
set count=0
FOR /F %%a in ('DIR /B %DataLoc%\*.tmp') do set /A count=count+1
if %count% GEQ %DataMax% (Goto Exit) else (GOTO FMove)
:FMove
Echo Gather Top 30 files
set SrcCount=0
set SrcMax=30
echo %HoldLoc%
FOR %F IN (c:\Play\hold\*.tmp) DO IF !SrcCount! LSS %SrcMax% (
SET /A SrcCount += 1
move /y %F "%DataLoc%"
)
Problem is that I get this in the output window, why won't the C be seen?
C:>set /A count=count+1
C:>if 19 GEQ 20 (Goto Exit ) else (GOTO FMove )
C:>Echo Gather Top 30 files
Gather Top 30 files
C:>set SrcCount=0
C:>set SrcMax=30
C:>echo C:\Play\Hold
C:\Play\Hold
\Play\hold\*.tmp) was unexpected at this time.
C:>FOR \Play\hold\*.tmp) DO IF !SrcCount! LSS 30 (
C:>
#echo off
set Source=C:\perl\Drift_Bat\IN
set Target=C:\perl\Drift_Bat\OUT
set MaxLimit=20
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
)
Your script uses incorrect syntax for the loop variable in one of the two loops:
FOR %F IN (c:\Play\hold\*.tmp) DO …
Just try changing %F to %%F. Single percent sign plus letter is the syntax for loop variables when running loops directly from the command prompt. In batch scripts you should always use double-percent references for loop variables, just like in your FOR /F %%a loop.
I updated the code and got it to work by changing some things. Thanks Andy for the tips but I could not get it to work with the suggestions - I wouldn't be surprised if I did not follow them and that is on MY side, not yours.
FOR /F %%G IN ('DIR /B "%HoldLoc%"\*.tmp') DO IF !SrcCount! LSS %SrcMax% (
SET /A SrcCount += 1
Echo "%HoldLoc%"
Echo "%%G%"
Echo "%SrcCount%
move /y "%HoldLoc%"\"%%G" "%DataLoc%"
)
Here is what I ended up with - longer but still functional:
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
echo on
set DataMax=50
set DataLoc=C:\Test Data (x86)
Set HoldLoc=C:\Test Hold
set count=0
FOR /F %%a in ('DIR /B "%DataLoc%"\*.tmp') do set /A count=count+1
if %count% GEQ %DataMax% (Goto Exit) else (GOTO FMove)
:FMove
Echo Gather Top 30 files
set SrcCount=0
set SrcMax=30
FOR /F "TOKENS=*" %%a IN ('dir /A-D /O-D /B "%HoldLoc%"\*.tmp') DO (
SET /A SrcCount += 1
if !SrcCount! LEQ %SrcMax% (
MOVE /y "%HoldLoc%\%%a" "%DataLoc%"
)
)
goto Exit
:Exit
close

Resources