Delete files less than a specific size - windows

I would like to delete all files that are less than a specific size in a directory. Does anyone know if there is a Windows command that will do this? something like del *.* where size<3kb
I am currently doing this:
for /F %%A in ("*.pdf") do If %%~zA LSS 20103409 del %%~fA
and the ouput I get is:
C:\Documents and Settings\agordon\Desktop\test>If 6440450 LSS 20103409 del C:\Do
cuments and Settings\agordon\Desktop\test\US Tox 01-06-11.pdf
The system cannot find the path specified.
...even though that PDF file is small enough to be deleted.
What am I doing wrong?
This is actually working:
FOR %%F IN (*.pdf) DO (
IF %%~zF LSS 20103409 DEL %%F
)
However it is not recognizing the file names because they have spaces! How do I convert the Windows name to a "DOS" name in that script? For example, the Windows name is file name.pdf I would probably need to convert to "DOS" and it would look like this file_name.pdf or something like that.

Try this from a batch script:
#echo off
setlocal
for /f "usebackq delims=;" %%A in (`dir /b *.pdf`) do If %%~zA LSS 3145728 del "%%A"

BTW: Using PowerShell (on Windows 10) was the easier way for me:
I only did this on the directory where I wish to delete files smaller than 20MB:
ls | where {$_.Length -lt 20mb} | Remove-Item

Ok so I used AtomicParsley in a cmd script to add artwork to all my MP4 movies in over 400 sub folders with the --overWrite option. It sometimes barfs and the orignal file is left at less than 2k. I needed a way to find all these messed up MP4 files so I can redownload them.
This is what I used from the command line using Mrchief's example and it works like a charm in windows 7.
#for /f "usebackq delims=;" %A in (`dir /s /b *.mp4`) do #If %~zA LSS 2048 echo "%A"
and this is the output after processing 32 of the files
D:\Movie>#for /f "usebackq delims=;" %A in (`dir /s /b *.mp4`) do #If %~zA LSS 2048 echo "%A"
"D:\Movie\Action\Deadland (2009)\Deadland (2009).mp4"
"D:\Movie\Science Fiction\Alien3 (1992)\Alien3 (1992).mp4"
D:\Movie>
you could replace the echo with del and change the 2048 to search for a different size.

Here is a different approach using robocopy and its filter capabilities. Here is an excerpt of the File Selection Options shown when robocopy /? is typed into the command prompt window:
/MAX:n :: MAXimum file size - exclude files bigger than n bytes.
/MIN:n :: MINimum file size - exclude files smaller than n bytes.
/MAXAGE:n :: MAXimum file AGE - exclude files older than n days/date.
/MINAGE:n :: MINimum file AGE - exclude files newer than n days/date.
/MAXLAD:n :: MAXimum Last Access Date - exclude files unused since n.
/MINLAD:n :: MINimum Last Access Date - exclude files used since n.
(If n < 1900 then n = n days, else n = YYYYMMDD date).
Hence the /MIN and /MAX options can be applied here. Since we do not want to copy any files, use the /L option to list all the items that would be copied without the switch, then parse the returned list by a for /F loop, which holds the actual deletion command del in the body:
set "TARGETDIR=."
set "FILES=*.pdf"
for /F "tokens=*" %%F in ('
robocopy "%TARGETDIR%" "%TARGETDIR%" "%FILES%" ^
/L /IS /FP /NC /NS /NDL /NP /NJH /NJS ^
/MIN:0 /MAX:3071
') do (
ECHO del "%%F"
)
After having tested, remove the upper-case ECHO from the script to actually delete files.
Besides /MIN, /MAX and /L, there are several other options defined in the robocopy command line, most of which care for the needed output, namely a simple list of full paths of matching files, without any extra information like headers, footers or summaries.
The source and destination directories are both set to our target directory. Normally this would not work, of course (you cannot copy files onto themselves), but since /L is stated, the file list is generated, but only if the switch /IS is given too (meaning that "same files" are to be regarded).

There isn't a switch in the Del command which will delete files based on filesize.

I am not sure how to do this from DOS, but this is something we have used in the past; it uses VBScript, so you would call this filesoversize.vbs.
Dim strPath
Dim lngSize
Dim fso
Dim fold
Dim files
Dim file
lngSize = 10000 ' The threshold in bytes (this is 100k)
strPath = "C:\temp\" 'The folder you want to start in
Set fso = CreateObject("scripting.filesystemobject")
Set fold = fso.GetFolder(strPath)
Set files = fold.files
For Each file In files
If file.Size <= lngSize Then file.Delete True
Next

Related

Create subfolders/zip every 20 files automatically

I have a huge folder that I would like to transform into several small ones of 20 files each and compressed. I would like to do this automatically with a batch file and 7zip.
To achieve this I thought about 2 steps:
1. Create a sub-folder for each 20 files (source) :
#echo off
set /a counter=1
set /a filesperfolder=20
cd "C:\Users\Desktop\dir\"
:loopstart
set dirname=dir_%counter%
md %dirname%
echo %dirname%
dir /b | findstr /v /i "dir_*"> %temp%\temp.txt && for /l %%l in (1,1,%filesperfolder%) do #for /f "tokens=1,2* delims=:" %%a in ('findstr /n /r "^" %temp%\temp.txt ^| findstr /r "^%%l:"') do #move %%b %dirname%\%%b >nul
set /a counter=%counter%+1
for /f "tokens=*" %%a in ('type %temp%\temp.txt ^| find /c /v ""') do set _filesmoved=%%a
del %temp%\temp.txt
IF %_filesmoved% LSS 20 goto done
goto loopstart
:done
cls
echo All files were moved!!
pause
exit
Unfortunately this does not work : The syntax of the command is incorrect.. I've tried debugging the script by removing the #echo off and it tells me that the dir /b | findstr /v /i "dir_*"> %temp%\temp.txt && for /l %%l in (1,1,%filesperfolder%) do #for /f "tokens=1,2* delims=:" %%a in ('findstr /n /r "^" %temp%\temp.txt ^| findstr /r "^%%l:"') do #move %%b %dirname%\%%b >nul part is not working (same error). This part is quite fuzzy for me and a little help would be welcome.
I specify that the file temp.txt contains my complete list of files, without any separator (one file per line).
--- UPDATE: filenames must not contain spaces ---
2. Compress all these subfolders one by one with (source) :
for /D %d in (*.*) do 7z a -tzip "%d.zip" ".\%d\*"
Do you have an idea for (I summarize) : create, for a large number of files, subfolders of 20 files in order to compress each subfolder one by one.
If you have any idea on how to compress each 20 files directly (without going through the creation of subfolders) I also agree!
Thank you in advance for your help!
Resolved!
I found my mistake. In reality my files included spaces that the script could not fit.
So, to answer my basic question which was: in a big folder filled with thousands of files, how to compress each 20 files in subfolders? it is necessary (to my knowledge) to:
Create a sub-folder for each 20 files whose name does not have spaces (code in my question)
Compress all these subfolders one by one (code in my question)
And it's done!
Do not hesitate to suggest a solution if you know of a "faster" one.
No need to create folders. Just iterate over the files and add every single file to it's designated zip file (instead of copying every 20 files into a folder and zip that folder)
Use two counters to keep track of (source)files and zip files. One counter for the files (use the Modulo-operator to check for each 20) and one for the zip filenames. I started the zip filenames with 10001 instead of 1 and took the last four chars of it to get sortable file names (0001.zip etc).
#echo off
setlocal enabledelayedexpansion
set filesperfolder=20
cd /d "%cd%"
set "zipDest=C:\temp"
set filecounter=0
set foldercounter=10001
for %%a in (*) do (
set /a filecounter+=1
set /a check=filecounter %% filesperfolder
if !check! == 0 set /a foldercounter+=1
ECHO 7z a -tzip "%zipDest%\!foldercounter:~-4!.zip" "%%a"
)
Obviously adapt the cd /d line (source folder), destination folder (Attention: don't use the source folder, or your zip files might be zipped again into other zip files), and maybe the zip-filename (like "%zipDest%\MyZips-!foldercounter:~-4!.zip")
NOTE: I disarmed the 7zip command with ECHO for testing and troubleshooting. Remove the ECHO when the output satisfies you.
To delete each file after successfully zipping them, change the zip line to:
7z a -tzip "%zipDest%\!foldercounter:~-4!.zip" "%%a" && del "%%a"
The quotes should take care of any spaces.

Open a random file from folder with Batch

I'm an artist who is learning programming and I wanted to create a batch file that will select a random picture file from my references folder. The goal being to get a random picture to work on and study. I've looked around and the replies I see are hard to understand and are often linked with other features and functions I don't need. Simply put, how do I make a batch file that opens a random picture file from a folder (and subfolders)? Do I need to index every picture and then have a selector from that or can I just use %random% to open it?
Thank you for your help.
This is the basic batch file structure you'll need:
#Echo Off
Set "SrcDir=C:\Users\Jiosen\references"
Set "ExtLst=*.jpeg *.png *.tiff"
Set "i=0"
For /F "Delims=" %%A In ('Where /R "%SrcDir%" %ExtLst%') Do (Set /A i+=1
Call Set "$[%%i%%]=%%A")
Set /A #=(%Random%%%i)+1
Call Start "" "%%$[%#%]%%"
You may need to adjust lines 2 and 3 as necessary, (but do not remove or add any doublequotes).
PowerShell is more efficient in selecting files in a tree and getting a random file so why not use it from the batch.
Taking Compos batch as a template:
:: Q:\Test\2018\07\24\SO_51487674.cmd
#Echo Off
PushD "C:\Users\Jiosen\references"
Set "ExtLst=*.jpg,*.jpeg,*.png,*.tiff"
For /F "Delims=" %%A In ('
powershell -Nop -C "(Get-ChildItem * -R -File -Incl %ExtLst%|Get-Random).FullName"
') Do Start "" "%%A"
Get-ChildItem parameters -File,?-Include and Get-Random require at least PowerShell Version 3.0
According to the table in this link you need to upgrade Window 7 PowerShell v2 to at least V3, Windows 8 or higher should run the script without problem.
But I'd recommend to upgrade to 5.1 and possibly install PowerShell 6.0 (core) in parallel.
#SETLOCAL ENABLEDELAYEDEXPANSION
rem #CD C:\newfolder
#set count=0
#For /f "delims=" %%A in ('dir C:\users\*.* /ad /s /b') Do (
# set /a count=!count!+1
#rem If !Count! gtr 1 echo Num of folders
)
#Set /a num=%random% %% %Count% + 1
Echo %num% / %count%
For /f "skip=%num% delims=" %%A in ('dir C:\users\*.* /ad /s /b') Do (
Echo this is nth random folder
Echo Copy "%~dpnx0" "%%A"
rem Exit /b
)
pause
%Random% gives us a random number from 0 to 32K. #Set /a num=%random% %% %Count% + 1 uses modulo division (ie the remainder from a division) of 32K divided by how many will give us a random number in the range 0 to count. Then add 1 to make it 1 to count +1 (the number of folders). Then skip=%num% skips the first how ever many folders, reads the next, then exits the loop.
This is limited to 32K folders. See Dir /? for how to list files and files in subfolders. Every command above plus /? for help. See http://stackoverflow.com/questions/41030190/command-to-run-a-bat-file/41049135#41049135 for a CMD cheat sheet.

Generate a list of the newest file in each subdirectory in windows batch

I have a need to determine what the newest file is in each subdirectory under a root folder and output that list to a text file showing both the filename and creation date. As an example, if the root directory is D:\Data which contains a total of 4 subdirectories, and one of those 4 contain a subdirectory, my output file should contain a list of only files (not including created folders) something like this:
D:\Data\folder1\filename 02/12/14
D:\Data\folder2\filename 03/02/14
D:\Data\folder3\filename 03/15/14
D:\Data\folder4\folder01\filename 01/22/14
I have checked other posts, but none seem do this specifically...
Two options
#echo off
setlocal enableextensions enabledelayedexpansion
set "rootFolder=c:\somewhere"
:: option 1
echo --------------------------------------------------------------------------------
for /d /r "%rootFolder%" %%a in (.) do (
set "first="
for /f "delims=" %%b in ('dir /o-d /a-d /b "%%~fa\*" 2^>nul') do if not defined first (
set "first=1"
for %%c in ("%%~fa\%%b") do echo %%~tc %%~fc
)
)
:: option 2
echo --------------------------------------------------------------------------------
set "tempFile=%temp%\%~nx0.%random%.tmp"
dir /a-d /b /s /o-d "%rootFolder%" 2>nul >"%tempFile%"
set "oldFolder="
for /f "usebackq delims=" %%a in ("%tempFile%") do if not "%%~dpa"=="!oldFolder!" (
echo %%~ta %%~fa
set "oldFolder=%%~dpa"
)
del /q "%tempFile%" >nul 2>nul
Option 1 will recurse over the folders structure and for each one, a dir command is executed to retrieve the list of files in the folder in descending date order. The first in the list is the most rececent one.
Option 2 will use only one dir command to retrieve the full list of files in descending date order and will save the retrieved information in a temporary file. Then the file is processed. Each time the name of the folder changes, output the first line that will be the most recent file in the folder.
Option 1 will start earlier to echo information, but as multiple commands are used, it will require more time to execute, but needs less memory as it will only retrieve the file list of one folder each time.
Option 2 uses less commands and will be faster, but uses a temporary file and requires more memory that Option 1 as the full file list will be loaded in memory.
Select depending of how deep is your folder structure, how much files you have, how much memory, .... just test.

Comparing Two Folders and its Subfolder batch file

I have two folders that contain all the same files and subfolders, but the conents inside each file may have changed. I want to write a batch file that will search through each file and look for any differences. What's the best tool for what I want to do?
No need for a batch file. A single FC command can do what you want:
fc folder1\* folder2\*
You can be more specific for the file mask in the first folder if you want. For example folder1\*.txt.
The command will report on files that exist in folder1 but are missing in folder2. Extra files in folder2 are simply ignored.
There are a number of options to the FC command. Enter HELP FC or FC /? from the command prompt to get more information.
EDIT
Extending the solution to support subfolders is a bit tricky. It is easy to iterate the folder hierarchy for a given root using FOR /R. The problem is getting the relative paths so that the hierarchy can be applied to another root.
The simplest solution is to use FORFILES instead, since it directly supports relative paths. but FORFILES is... S L O W :/
At this point, a batch file makes sense:
#echo off
setlocal
set "folder1=c:\path\To\Folder1\Root"
set "folder2=d:\path\To\Folder2\Root"
set "fileMask=*"
for /f "delims=" %%F in (
'echo "."^&forfiles /s /p "%folder1%" /m "%fileMask%" /c "cmd /c if #isdir==TRUE echo #relpath"'
) do fc "%folder1%\%%~F\%fileMask%" "%folder2%\%%~F\*"
Here is another way to accomplish the task. Set the variables Folder1 and Folder2 to the full path of the folders you want to compare and run the batch file.
Output:
Dup – the file exists in both folders and are identical.
Dif - the file exists in both folders but the content of the files are different.
New – The file exists in one folder but not the other.
#Echo Off
SetLocal EnableDelayedExpansion
Set "Folder1=%UserProfile%\Desktop\Test Folder1"
Set "Folder2=%UserProfile%\Desktop\Test Folder2"
For /R "%Folder1%" %%x In (*.*) Do (
Set "FullPath=%%x"
Set "RelPath=!FullPath:%Folder1%=!"
If Exist "%Folder2%!RelPath!" (
>Nul 2>&1 FC /b "%Folder1%!RelPath!" "%Folder2%!RelPath!" && (
Echo Dup - %%x
)||(
Echo Dif - %%x
)
) Else (
Echo New - %%x
)
)
For /R "%Folder2%" %%x In (*.*) Do (
Set "FullPath=%%x"
Set "RelPath=!FullPath:%Folder2%=!"
If Not Exist "%Folder1%!RelPath!" (
Echo New - %%x
)
)
I'm having better luck with the following batch file. The path names have to completely match though; so only the Drive Letter differs.
Mapping a shared network folder may make this easier. I can't say for sure for your case.
'---
setlocal
set "folder1=D:\User\Public"
set "Drv2=E:"
set "fileMask=*"
setlocal
set "folder1=<DrvLttr>:\<Folder>\<SubFolder>"
set "Drv2=<DrvLttr2>:"
set "LogFile=<SystemDrv>\User\<UserName>\<LogFileName>"
ECHO "the '>' may OVER WRITE or make a ~NEW~ File for the results" > "%LogFile%"
ECHO " '>>' adds to the end of the file >> "%LogFile%"
FOR /R %folder1% %%A in ( *.* ) DO FC "%%A" "%Drv2%%%~pnxA" 1>> "%LogFile%" 2>&1
If you wish to note what is going to be the command for testing, you can try inserting ECHO after DO. You can drop the 1>>... stuff to see the result on screen, instead of having to open the output file.
I modified a batch file I wrote for a CD process that should meet your need. It
takes 2 directory trees and compares each file in each tree
creates a list of the file differences (named File_differences.txt in the output folder)
and creates a folder with a diff file for each non-matching object
If both directory structures are under the same parent, then all you need to do is update the first 8 variables in the script. If the directory trees have different parents, then read through the scripts comments. Particularly lines 14, 38 and 46.
:: This script compares the contents of 2 trees
:: set a workspace location for the script outside of the trees being reviewed
set home=D:\path\to\batch_file_home
set Input=D:\path\to\batch_file_home\Input_Files
set Resource=D:\path\to\batch_file_home\Resource_Files
set Output=D:\path\to\where your want to view your\Output_Files
set environment=D:\path\to\parent directory containing the different tree structures (if they do not share a parent, then make this the drive)
:: the next 3 lines are only needed if you want to predefine multiple directories for comparison
set Prod=production
set QA=test
set Dev=branches\dev
:: If you remove the 3 lines above, then you need to replace the 2 below variables with values
:: If the trees are not under the same parent, then include the full path for Tree A and B below
set Tree_A=%Prod%
set Tree_B=%QA%
:: if you already have an object list, place it in the Input folder and remove lines 24 through 35 of this script
set Object_List=Object_List_minus_Direcotries.txt
set Output_File=File_differences.txt
if exist %Output%\%Output_File% del %Output%\%Output_File%
if exist %Output%\Differences\*.txt del %Output%\Differences\*.txt
if exist %Resource%\* del /q %Resource%\*
:: since you state the objects in both trees are always the same, I have not included a comparison to verify the 2 trees match
:: this section identifies the contents of Tree A
cd %environment%\%Tree_A%
dir /b /s > %Resource%\Complete_Tree_A_Object_List.txt
:: Next, remove the objects that are directories
setlocal enabledelayedexpansion
for /f "tokens=*" %%p in (%Resource%\Complete_Tree_A_Object_List.txt) do (
dir /a:d /b %%p 2>nul >nul && (set object_type=folder) || (set object_type=file)
echo !object_type!
if !object_type!==file echo %%p >> %Resource%\%Object_List%
)
:: in the object list, remove the parent tree from the path
:: if the Trees are not under the same parent, then comment out the below 6 lines
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '\\','/' | set-content %Resource%\%Object_List%"
powershell -command "(get-content %Resource%\%Object_List%) | Foreach {$_.TrimEnd()} | Set-Content %Resource%\%Object_List%"
set remove_parent_prefix=%environment%\%Tree_A%
set remove_parent_prefix=%remove_parent_prefix:\=/%
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '%remove_parent_prefix%/','' | set-content %Resource%\%Object_List%"
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '/','\' | set-content %Resource%\%Object_List%"
:: the below loop assumes both Trees are under the same parent. If this is not the case, replace the cd %environment% line with cd %home%
:: when the Trees are not under the same parent, set home to the root location, example cd D:\
setlocal enabledelayedexpansion
for /f "tokens=*" %%x in (%Resource%\%Object_List%) do (
set Diff_File=%%x
set Diff_File=!Diff_File:\=-!
cd %environment%
fc %Tree_A%\%%x %Tree_B%\%%x > "%Output%\Differences\!Diff_File!-%Output_File%"
for %%a in ("%Output%\Differences\!Diff_File!-%Output_File%") do for /f %%b in ('find /c /v "" ^< "%%a" ') do if %%b LSS 3 del "%%a"
for %%R in ("%Output%\Differences\!Diff_File!-%Output_File%") do if not %%~zR lss 1 (
echo %%x >> %Output%\%Output_File%
)
for %%R in ("%Output%\Differences\!Diff_File!-%Output_File%") do if %%~zR lss 1 (
del "%Output%\Differences\!Diff_File!-%Output_File%"
)
)
endlocal
:: Clean up Resources. If you want to review the temp files used to create the report, comment out the below line
if exist %Resource%\* del /q %Resource%\*

Exclude specific file extension

Alright, I'm new to scripting and I'm trying to edit a batch script file that sends an email when a file with an extension of .ecl is in a folder longer than 5 min or so. But there are other files with a .ecl.part extension that get flagged and it sends an email instead of the .ecl files. I'm curious if there is something I can add so that it will send an email when there are .ecl files in the folder for more than 5 min and ignore the .ecl.part files. I read one for someone with Linux who used [!(.extension to exclude)].extension not to exclude, I'm just wondering if this will work for my windows batch script. If it will work do I add it just like that or do I add it like this .extension not to exclude[!(.extension to exclude)]
Here is the part of the script in question:
for /f "tokens=1-5 delims=:, " %%a in ('forfiles /p z: /d +0 /s /m *.ecl /c "cmd /c if #isdir==FALSE echo #file,#ftime"') do (
set fnam=%%a
set fhr=%%b
set fmin=%%c
set fsec=%%d
set fampm=%%e
if "!fampm!" == "PM" if "!fhr!" neq "12" (set /a "fhr=!fhr!+12")
There is more of the script, I didn't set this up, and the person who did isn't being very helpful which is why I came here.
#ECHO OFF
SETLOCAL
SET savearea=c:\destdir
SET emldir=c:\sourcedir
ECHO.>"%savearea%\emlfiles.new"
DIR /b /a-d /on "%emldir%\*.eml" >>"%savearea%\emlfiles.new"
IF NOT EXIST "%savearea%\emlfiles.old" GOTO noold
FOR /f "usebackqdelims=" %%i IN ("%savearea%\emlfiles.new") DO (
FINDSTR /b /e "%%i" "%savearea%\emlfiles.old" >NUL
IF NOT ERRORLEVEL 1 (ECHO %%i is MORE than 5 minutes old)
)
:noold
MOVE /y "%savearea%\emlfiles.new" "%savearea%\emlfiles.old" >nul
GOTO :eof
This script saves in %savearea% a sorted basic filelist of the *.eml files in %emldir% then compares the new list to the previous version. If the same filename appears in both, it will generate the message %%i is MORE than 5 minutes old
So - all you need to do is point emldir to wherever your .eml files reside, savearea to some safe directory, replace the message ECHOing with an email-sending command of your liking and schedule it to run each 5 minutes using task scheduler.
Although in my testing I find this not to be the case, it sounds like forfilesis evaluating wildcards against 8.3 short filenames on your computer. You know how if you're in a directory containing both .doc and .docx files and you do a dir *.doc, the .docx files will be listed as well? Same sort of thing.
So *.ecl is matching your .ecl.part files because in 8.3 notation they've got a .ecl extension. You could either make sure %fnam:~-4%==.ecl, enclosing most of the guts of your for loop within an if statement; or you can use find or findstr to filter the output of forfiles as captured by the for loop. Something like this:
for /f "tokens=1-5 delims=:, " %%a in (
'forfiles /p z: /d +0 /s /m *.ecl /c "cmd /c if #isdir==FALSE echo #file,#ftime" ^| find /v /i ".part"'
) do (
set fnam=%%a
set fhr=%%b
set fmin=%%c
set fsec=%%d
set fampm=%%e
if "!fampm!" == "PM" if "!fhr!" neq "12" (set /a "fhr=!fhr!+12")
rem etc.
Since find /v prints lines not matching its search, that should effectively filter out the .ecl.part files. find /v works like grep -v in Linux.
You know, since my test cases don't seem to match the symptom you're describing, I am very curious to know whether simply replacing if #isdir==FALSE with if #ext==\"ecl\" would also prevent the .ecl.part files from being included. But if you don't feel like experimenting to satisfy my curiosity, I totally understand.

Resources