Batchfile to delete all folders but the latest AND a special folder - batch-file

hope you can help me. I am looking for a way to use batchscript to delete all folders in a subfolder except
the very newest folder AND
a special folder named "BACKUP".
So the backup folder can be older, but it needs to be kept.
All other folders except the one with the newest date should be deleted.
There will be files in all of those folders, but there are no hidden files or subfolders, so this needs not to be considered in this case.
I found a lot of solutions here to either spare the backup folder or delete everything except the newest, but I cannot seem to find a solution that can do both.
for /d %%i in ("C:\Parent\*") do if /i not "%%~nxi"=="BACKUP" del /s /q "%%i"
I.e. like this, but it will not keep the newest folder.
All the other folders except the backup folder have names like "20220215" "20210405".
Thank you for any help you can give.
KR
Susanne

Build a list of directories by dir sorted by age from newest to oldest, filter out unwanted ones by findstr, then use for /F to iterate through the list but skip the very first item:
rem // Change into root directory:
pushd "C:\Parent" && (
rem /* Loop through matching directories sorted by last modification date (due to `/T:W`)
rem in descending order and skip the very first (that is the lastly modified) item: */
for /F "skip=1 delims= eol=|" %%I in ('
dir /B /A:D-H-S /O:-D /T:W "????????" ^| findstr /V /I /X "BACKUP"
') do rd /S /Q "%%I"
rem // Return from root directory:
popd
)
Since del only deletes files, rd is used instead to delete (sub-)directories too rather than leaving behind empty (sub-)directory trees.
The line dir /B /A:D-H-S /O:-D /T:W "????????" ^| findstr /V /I /X "BACKUP" could be replaced by the following in order to do stricter filtering:
dir /B /A:D-H-S /O:-D /T:W "????????" ^| findstr /I /X "[12][0123456789][0123456789][0123456789][01][0123456789][0123][0123456789]"

set "skipme=Y"
for /f "delims=" %%b in ('dir /b /ad /od "c:\parent\*"') do if /i "%%b" neq "backup" if defined skipme (set "skipme=") else (ECHO rd /s /q "c:\parent\%%b")
Should remove all the required directories. Well, report the directorynames that would be delete if the echo keyword was deleted.
skipme is initialised to a value. for each directory found, with the exception of backup, check whether skipme has a value; set skipme to empty if it's set (which will only be for the first directory found that isn't backup from a date-ordered dir list), otherwise remove the directory.

Related

How to sort and delete old directories based on the folder name which is in date

So I have a folder called Folder1 and inside of that folder has multiple other Folders for our build. The naming convention of those build folders are the date that they were built. For example: 20190314141438 (which is 2019-03-14 time 14:14:38). So what I like to do is to delete everything except for the last latest 3 folders. I started it out in a batch script but was able to delete it based on last modified date, which works, but need to somehow compare all the folders name and delete the old ones. Here is my script:
if not exist "%Location%" (
echo The Location - "%Location%" does not exist
) ELSE (
for /F "skip=3 delims=" %%i in ('dir "%Location%" /AD /B /O-D 2^>nul') do (
echo Removing "%Location%\%%i"
rd /Q /S "%Location%\%%i"
)
)
I was also thinking if it's not possible with a batch script, I can create a java program that does that if anyone has any idea on how i should start. Thanks.
UPDATE:
Some of the folders will also have a release number at the end of the folder name such as 20190314141438_Release2. How would I tell the batch file to ignore those. I was thinking of using findstr /C:"Release1"and somehow put that in a if else statement?
Thank you LotPings and Mofi for helping me out with this question. I have posted the script that works:
if not exist "%Location%" (
echo The Location - "%Location%" does not exist
) ELSE (
for /F "skip=3 delims=" %%i in ('dir "%Location%" /AD /B /O-N 2^>nul ^|
%SystemRoot%\System32\findstr.exe /I /V /C:Release') do
echo Removing "%Location%\%%i"
rd /Q /S "%Location%\%%i"
)
)

In batch, how to list files of a specific directory?

I need to go through all the directories except one (named "FORBIDDEN"), and to print for each of them all the files they contain.
So I wrote a batch script like this:
#echo off
for /f "tokens=*" %%G in ('dir /b /s /a:d %cd%') do ^
if %%G NEQ C:\Users\ME\FORBIDDEN (dir /a-d %%G)
But the part (dir /a-d %%G) is not good because I get some errors saying that files were not find.
So, for each round of the loop, how to list all files present in the directory (whose path is in %%G) ?
Cheers
for /d /r %%d in (*) do if not "%%~nxd"=="FORBIDDEN" 2>nul dir /a-d "%%d"
For each folder if it is not the excluded one, show its contents
edited to adapt to comments
To only include the files with full path
for /d /r %%d in (*) do if not "%%~nxd"=="FORBIDDEN" (
for %%f in ("%%~fd") do echo "%%~ff"
)
Another option (that also includes files in the current folder) could be
dir /a-d /s /b | find /v "\FORBIDDEN\"
Get the full list and filter it, to only retrieve the lines that does not make reference to the excluded folder

Batch script to search multiple directory and move it to a specific folder

I want to create a script that searches a multiple directory "eg: TEST" and move it to a specific location in a folder. I have tried using the below script. It display the folder location
example:
"E:\Example\TEST"
"E:\TEST\TEST"
Please check the script i have created. Can anyone help?
#echo off
set filename=TEST
set searchPath=E:\
set Destination= E:\FOUND
FOR /R "%searchPath%" %%a in (%filename%) DO (
IF EXIST "%%~fa" (
echo "%%~fa"
)
)
move "%%~fa" "%Destination%"
There are several problems:
Since you are trying to move directories, the directory tree enumerated by for /R is modified. for/for /R however does not enumerate the directory (tree) in advance, therefore unexpected results may occur -- see the following question for details about that: At which point does for or for /R enumerate the directory (tree)?.
for or for /R accesses the file system only in case there are wildcards given in the set (that is the part in between parentheses).
It is not perfectly clear what exactly you want to accomplish:
what should happen in case of conflicting items? overwrite them or not? merge (sub-)directories?
in case of E:\TEST\TEST, do you want E:\TEST to be moved at once, so there is no more directory TEST at E:\?.
Note that the move command cannot be used because it causes trouble when moving directories and the destination directory already exists (Access is denied. errors occur).
Item 1. can be solved by a nice work-around using for /F and dir:
for /F "eol=| delims=" %%I in ('dir /B /S /A:D "E:\TEST"') do echo(%%I
This enforces the entire directory tree to be enumerated (read) before the loop iterations start.
However, this introduces another problem similar to item 2.: when a name is given for dir that matches a directory existing in the given location, its content is returned rather than all items matching that name. What I mean is the following:
dir /B /S /A:D "E:\" returns all directories (/A:D) at E:\ recursively (/S);
dir /B /S /A:D "E:\file.ext" returns all directories called file.ext, even if there is a file named E:\file.ext;
but: dir /B /S /A:D "E:\TEST" returns all sub-directories of E:\TEST, but not E:\TEST itself;
however: dir /B /S /A:D "E:\TEST*" returns all directories beginning with TEST, also those in E:\; to exactly match the name TEST, additional filtering is required (using findstr);
All this means:
for /F "eol=| delims=" %%I in ('dir /B /S /A:D "E:\TEST*" ^| findstr /I /E /C:"\\TEST"') do echo(%%I
Item 3. can only be solved by you, but to provide a complete answer, I make some assumptions:
(sub-)directories are merged, already existing items are overwritten without notice;
parent directories take precedence over sub-directories (like for /R and dir /S behave, because for every branch in a tree, they always go from higher down to lower directory levels);
Item 4. can be solved by using command robocopy together with option /MOVE instead of move.
So here is the final script:
#echo off
rem // Define constants here:
set "_PATH=E:\"
set "_NAME=TEST"
set "_DEST=E:\FOUND"
2> nul mkdir "%_DEST%"
for /F "eol=| delims=" %%I in ('
dir /B /S /A:D "%_PATH%\%_NAME%*" ^| findstr /I /E /C:"\\%_NAME%"
') do (
> nul robocopy "%%I" "%_FOUND%\%_NAME" /E /MOVE
)
The > nul portion is intended to suppress progress and log messages and to suppress The system cannot find the path specified. errors in case E:\TEST\TEST is attempted to be moved although it does no longer exist since the parent E:\TEST has alread been moved before.

How to delete specific hidden sub folders recursively with batch

A bad program left several ".data" hidden folders in every sub directory.
I have tried this so far, and it doesn't work...
RD /ah /s /q "D:\This Folder\.data"
I have many folders and sub-folders, each one has a ".data" hidden folder there that I would like to remove. If it helps, I would like to delete all the hidden folders because they are all ".data".
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "delims= eol=" %%a in ('
dir /adh /s /b 2^>nul
') do if /i "%%~nxa"==".data" echo rd /s /q "%%~fa"
This executes a dir command to retrieve a recursive (/s) list of hidden directories (/ahd) in bare format (/b). This list is processed by a for /f command that will check for each match if it is a .data folder. If it matches the condition, the folder and its contents are removed.
note the rd commands are only echoed to console. If the output is correct, remove the echo command.
#ECHO OFF
for /f "tokens=*" %%F in ('dir /s /b /o:n /adh') do (
if "%%~nxF"==".data" rd /s /q "%%F"
)
dir /s /b /o:n /adh gives you all folders and subfolders skipping files. for /f iterates over all these folders. %%~nxF extracts the last folder name from the whole path so we can check whether it is .data. If this is the case rd /s /q %%F deletes the folder.
Read what you get when you type for /? then:
Use the /d
FOR /D %variable IN (set) DO command [command-parameters]
If set contains wildcards, then specifies to match against directory
names instead of file names.
and the /r switches together
FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
Walks the directory tree rooted at [drive:]path, executing the FOR
statement in each directory of the tree. If no directory
specification is specified after /R then the current directory is
assumed. If set is just a single period (.) character then it
will just enumerate the directory tree.
To scan folders recursivly
for /d /r . %%a in (data*) do rd /s /q "%%a"

Is it possible to skip over a subdirectory when performing an operation over an entire directory?

So I have this code for sorting files within a complex of subdirectories within a main directory:
#ECHO OFF
SETLOCAL
SET relroot=g:\Pictures\Uda 18
(SET relroot=g:\Pictures\Uda 18)
SET "relroot=g:\Pictures\Uda 18"
SET "destdir=g:\Pictures\Uda 18\Sets"
:again
(SET artist=)
SET /p artist="Artist? "
IF NOT DEFINED artist GOTO :eof
MD "%destdir%\%artist%" 2>nul
FOR /f "delims=" %%i IN (
' dir /s /b /a-d "%relroot%\*%artist%*" '
) DO (
>>undo.txt ECHO %%i^|%destdir%\%artist%\%%~nxi
MOVE "%%i" "%destdir%\%artist%\%%~nxi" >nul)
)
GOTO again
It takes an input, searches the directory 'Uda 18' and everything within it, and moves all files with the input in their names to a folder named after the input under the directory 'Uda 18/Sets'. However, careless testing has caused me to draw files from 'Uda 18/Sets', the names of which mean they can't be reorganised using the batch. To avoid this, I need to exclude 'Uda 18/Sets' from where files are taken from, but I can't find a way. So as the titles asks; is it possible to skip a select subdirectory, and if so, how?
personally, I would prefer creatíng a destination-directory BESIDES the source-directory, not within:
source: g:\pictures\uda 18\xxx
destination: g:\pictures\sorted\uda 18\xxx
This way you do not only avoid that problem, you will also allways have a clear and consistent directory-structure
I too would separate my destination folder from the folders to be processed.
Moving it out and moving it back later is an option though.
move "g:\Pictures\Uda 18\Sets" "g:\Pictures"
do your other commands here
move "g:\Pictures\Sets" "g:\Pictures\Uda 18"
FOR /f "delims=" %%i IN (
' dir /s /b /a-d "%relroot%\*%artist%*" ^|findstr /v /i /b /c:"%destdir%\\"'
) DO ( ECHO MOVE "%%i" "%destdir%\%artist%\%%~nxi")
Should list the MOVE to be performed /v EXCLUDING any directory /b beginning /i case-insensitive /c: the entire string including spaces ... where \ escapes \ so therefore excluding "g:\Pictures\Uda 18\Sets" and any of its subdirectories (where the full filename would begin g:\Pictures\Uda 18\Sets\"
simply remove the /v to select ONLY the matching files in "g:\Pictures\Uda 18\Sets" and its subdirectories.
Try this to draw the file names except those from the "sets" folder:
dir /b /s /a-d "uda 18" | find /v /i "sets"
... and with your folders:
echo "%destdir%\%artist%" | find /v /i "sets" >nul && goto:createFolder || goto:eof

Resources