Batch / CMD script to delete folder but excluding more than one - batch-file

In advance: I'm new to batch or programming in general so please explain as much as possible.
My problem:
I want to delete all folders not named X and Y in a directory Z (ex. D:\Test\z)
So let's say Z contains these folder:
backup
resources
project1
project2
project3
I'd need to exclude only backup and resources from deletion via a script.
I looked up multiple soultions for not deleting only one folder with a certain name but I don't know if it's possible for multiple values with Batch.

not tested:
#echo off
set "root_dir=C:\Z"
set "exclude_list=backup resources"
pushd "%root_dir%"
for /f "tokens=* delims=" %%# in ('dir /b /a:d^| findstr /v "%exclude_list%"') do (
echo rd /s /q "%%~f#"
)
if this looks ok delete the echo on the last line to activate deletion.
If all folders you want to delete are like project* you can try also :
for /d %%a in ("project*") do rd /s /q "%%~fa"

#echo off
setlocal EnableDelayedExpansion
rem Define working variables
set "dir=D:\Test\z"
set "exclude=/backup/resources/"
rem Change current dir to working dir
cd /D "%dir%"
rem Process all folders in this dir
for /D %%f in (*) do (
rem If current folder is not in "exclude" var
if "!exclude:/%%f/=!" equ "%exclude%" (
rem Delete it
ECHO rd /s /q "%%f"
)
)
This method use internal cmd.exe commands only, so it run faster than other methods that may use external .exe files (like findstr.exe).
The way to detect if a name is in the exclude variable is trying to delete such name from it: "%exclude:/%%f/=%": if the result is equal to the original variable contents, the folder was not there. This method is very simple and efficient and works not matter the case of the letters, so it don't requires any /I ignore case switch in the if command.
The names are delimited by slashes to avoid any problem caused by partial name matches; for this reason the %%f part is enclosed in slashes in the if command.
Note that the value of %%f change in each iteration of the for command. For this reason, the exclude variable is surrounded by exclamation marks instead percent signs and the setlocal EnableDelayedExpansion command is given at beginning; otherwise, the %expansion% would be done just one time, before the for command start iterations. You may look for "delayed expansion" in this forum for a further explanation of this point.

Related

Renaming multiple files with no pattern

I'm starting to learn how to use the CMD in Windows. And I have a directory full of documents with names like "Document_1.txt", "Document_5.txt" etc... (All with Document_#.txt but there's no pattern in the numbers).
I want to move each file to a folder named "Text_#" and change the name of the file to "text_#.txt". How can I do that?
My attempt is this (simple) batch file (actually I think I don't even need to create a batch file, but was easy to do this way.)
#ECHO OFF
FOR /L %%i IN (1,1,24) DO (
FORFILES /M *.txt /C "cmd /c IF #fname==Document_%%i (MD Text_%%i) & (MOVE #file Text_%%i\text_%%i.txt)"
The problem is that the IF command never returns true, although when writing ECHO #fname it prints "Document_#", so I suppose that even if what I see is the same there is some difference that I cant see using the ECHO command.
Anybody could give me some solution to this problem?
In my opinion the simplest way is to forget about using the ForFiles command for this, and use a For /F loop instead. To ensure that only the files with a .txt extension whose basename ends with _# or _##, (where # represents an integer), use the Dir command and filter its results with the help of FindStr. Then you can use MD to make the directories if it don't already exist and move the files into it, renaming them with their new name.
From the cmd with the current directory as that holding your files:
For /F "Tokens=1,* Delims=_" %G In ('Dir /B /A -D Document_??.txt ^| %__AppDir__%findStr.exe /I "_[0123456789]*\.txt$"') Do #If Not Exist Text_%~nH (MD Text_%~nH) & Move /Y %G_%H Text_%~nH\text_%H 1>NUL
If you want to do that from a batch-file instead, also within the same current directory:
#For /F "Tokens=1,* Delims=_" %%G In (
'Dir /B /A -D Document_??.txt ^| %__AppDir__%findStr.exe /I "_[0123456789]*\.txt$"'
) Do #(
If Not Exist Text_%%~nH MD Text_%%~nH
Move /Y %%G_%%H Text_%%~nH\text_%%H 1>NUL
)
The above answers assume either one or two digits at the end of the file basenames, (as you were limiting yours to numbers from 1 to 24 inclusive) I have also left out quoting because your provided names didn't warrant it. If those were not truly representative, you'll need to introduce those as necessary and make any other changes which were outside of the question posed.

Scheduled Folder Cleanup - Batch File

I am currently working at my first Junior IT position, and I am having trouble with a simple batch file.
Essentially the file is ran weekly through the task scheduler. It removes files and folders from a server directory that are older than 8 days. It is also supposed to remove empty folders.
forfiles /p "P:\blahblah" /s /m * /d -8 /c "cmd /c del /Q /S /F /A #path"
cd /d P:\blahblah
for /f "usebackq" %%d in (`"dir /ad/b/s | sort /R"`) do rd "%%d"
REM robocopy "P:\blahblah" "P:\blahblah" /s /move"
There are two problems here;
It will occasionally delete files only a few days old.
It will not remove empty folders.
The file was written by an old junior IT employee and there is no documentation. My guess is multiple methods were used in order to ensure the cleanup (ironically). I have searched google and here are my current thoughts on each command..
1) forfiles - the forfiles command seems to be written correctly and I do not see any issues with it.
2) cd - simple enough
3) for - not entirely sure. The batch variables are new to me and I am not sure if it is working correctly.
4) robocopy - I have not been able to find an instance online where someone copies a directory to itself for cleanup. I also notice the extra quotation in there, but i am not certain of its incorrectness. This line especially seems odd to me.
Normally I would try and test my through something like this, but It is a bit harder to test quickly given I need to see if it is removing things based on calendar date. That's why I am here!
I promise I would not have asked if I had not already scoured the internet for an idea. Any help would be greatly appreciated, and I would love to learn a little more about the above commands!
Thanks for your help!
forfiles
Being syntactically correct doesn't mean it does what you want, it does what you ask. Here the problem is the del command. It will delete what the forfiles has selected, but you should test the selected element is not a folder. If you call del /q /s /f /a with a folder reference, you delete the folder contents.
cd
Simple enough, but as you don't check the operation was sucessful (maybe P: is not available) maybe the following for command removes information where it should not.
for
As Squashman comments, if you change the back quotes into single quotes you will not need the usebackq.
But you need the delims clause to avoid problems with paths containing spaces. for /f does not iterate over file references, but over lines of text (in this case generated by a dir command). By default tabs and spaces are delimiters that split the lines being processed and, also by default, only the first token is retrieved. Setting the delims clause to an empty list of characters will disable this behaviour.
You can try with something like
#echo off
setlocal enableextensions disabledelayedexpansion
pushd "p:\blahblah" && (
forfiles /s /m * /d -8 /c "cmd /c if #isdir==FALSE del /q /f /a #path"
for /f "delims=" %%d in ('" dir /ad /s /b | sort /R "') do rd "%%d"
popd
)
The pushd will change the current active directory to the required one. If the command is sucessful, the conditional operator && (execute next command if the previous one did not fail) will execute the rest of the code, restoring the active directory at the end.
4) robocopy
It can be used to do the clean, but not from a folder into itself.
#echo off
setlocal enableextensions disabledelayedexpansion
pushd "p:\blahblah" && (
rem Use a random temporary folder
for %%t in ("%temp%\clean_%random%%random%%random%%random%.tmp") do (
rem Select the files to keep
robocopy "." "%%~ft" /MAXAGE:8 /CREATE /s /njh /njs /nfl /nc /ns
rem Remove anything not selected
robocopy "%%~ft" "." /NOCOPY /PURGE /e /njh /njs /nfl /nc /ns
rem remove temporary folder
) & rd /s /q "%%~ft"
rem Restore previous active directory
popd
)
This code creates a replica of all the selected files (not older than 8 days) into a temporary folder, but the /CREATE switch tells robocopy to not copy the files, but to create 0 bytes files into the temporary target.
Once we have a replica with only the selected elements, the oposite operation is done, from temporary folder into work folder but requesting that no copy operation should be done (/NOCOPY), just a removal of elements not present in source (/PURGE).

Copy all ini from one folder for all users to another folder

I am trying to copy all .ini files from the Windows folder into a new folder I have already created. I need this to loop through for all users. Here is what I have but it only works for the last user, not each of them. This is a batch file.
for /r  %%f  in ("D:\Home\*.*\windows") do
set dir="%%d
for /r "%dir%\windows\" %%f in (*.ini) do (
copy %%f "%dir%\temp_ini"
))
pause
Please help :/ Thank you
You've got a few problems -- unterminated quote on the second line, not delaying the expansion of %dir% (and indeed, setting %dir% is unnecessary, anyway), illogical use of for /r in the first line, trying to recycle %%f in nested loops, and your *.* wildcard in the first line will only match directories containing a dot. You should also make sure the temp_ini directory is outside the scope of your search for ini files; otherwise, Windows will attempt to copy the contents of temp_ini\*.ini into itself recursively. Try this instead:
for /d %%I in ("D:\Home\*") do (
rem // create directory if not exist
if not exist "%%~I\temp_ini" md "%%~I\temp_ini"
rem // capture the output of dir /s /b
for /F "delims=" %%x in (
'dir /s /b "%%~fI\Windows\*.ini" 2^>NUL'
) do copy /y "%%~fx" "%%~I\temp_ini\"
)
pause

I need to create a list of folders that contain a specific file type with a batch file

Using a batch file I'm trying to generate a list of only folders within a location that contain a certain file type, let's call it *.abc
at the moment I only know how to echo a DIR command output to a file called folder.lst, I would like to expand on that and try to either
a) echo only folders containing the *.abc file type to folder.lst
b) remove references in folder.lst of folders that do not contain the *.abc file type.
I also tried having a FOR loop check each line to see if a *.abc file existed in that location and skip it, if not, but I just could not get that to work, here is an example of what I had.
setlocal enableextensions enabledelayedexpansion
FOR /F "delims=" %%C in (folder.lst) do (
set temp=%%C
if not exist !temp!\*.abc (goto skip) else (goto resume)
:resume
then my actions live here
:skip
)
but I am aware I am doing something wrong here...I just do not know what.
Maybe the /R form of the for command will help:
for /r "basedir" %%a in (.) do if exist "%%~a\*.abc" (
echo %%a contains .abc file(s)
)
The %%a will be the directories you want (with a trailing \., but you should be able to not care or accommodate this).
There are problems with such of the script as you have posted in that you can'y use labels within a block statement. You've also not provided any examples.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "lastdir="
FOR /r "%sourcedir%" %%a IN (*.abc) DO IF "!lastdir!" neq "%%~dpa" (
SET "lastdir=%%~dpa"
ECHO %%~dpa
echo "!lastdir:~0,-1!"
)
GOTO :EOF
Each directory found will be echoed twice - one with the trailing \ and once without.
You would need to change the setting of sourcedir to suit your circumstances.
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
for %%a in ("%root%") do for /f "delims=: tokens=2" %%b in ('
dir /a-d /s "%root%\*.abc" ^| find "\"
') do echo(%%~da%%~pnxb
This executes a recursive dir command searching for the indicated file type under the starting point (change root variable to suit your needs). For each found folder we retrieve the folder from the dir header that precedes the file list (the lines that contain a backslash).
To separate the path from the rest of the information in the line, the colon is used as delimiter. As this will leave the drive out of the retrieved information, an aditional for is used to retrieve the drive from the folder reference.
From the command line:
for /f "delims=" %a in ('dir /s /b *.abc') do echo %~dpa >> folders.lst
In a batch file:
for /f "delims=" %%a in ('dir /s /b *.abc') do echo %%~dpa >> folders.lst
The above commands will place only the folder names containing the *.abc files in folders.lst.
Notes:
% should be replaced by %% when the command is used in a batch file.
The ~dp part of %~dpa expands %a to a drive letter and path only. Remove the d if you don't want the drive letter. The p path includes a trailing \ which may be interpreted as an escape character by some commands.
The above commands start the search in the current directory. To search from the root of the current drive you can do cd \ first.
For more information see FOR /F Loop command: against the results of another command and Parameters.

Batch find certain filenames then use the names in variable

I need help with a script that first finds all files in a directory with a certain string, then uses the filenames in a variable to be used in a script.
So:
Find files and filenames
Saves file?
Start some kind of loop? that changes a variable then executes the
belonging script
Repeat till all filenames have been used.
My code here..
#Echo off
For /r C:\work %%G In (*) Do #Findstr /M /S "string" > filenames.txt %%G
Set Var1=0
For %%G In (*) Do (
Var1=<filenames.txt (???)
script
script
I haven't writen "script" myself and friend help me with it, if you would like to see it do you need to wait until I can get to my other computer at home.
Thanks on beforehand!
Find files and filenames
Saves file
set "search=what I want to find"
(for /f "delims=" %%a in ('dir /a-d /b /s "C:\work" ^| findstr "%search%"') do echo (%%~fa)>filenames.txt
Start some kind of loop? that changes a variable then executes the belonging script
Repeat till all filenames have been used.
for /f "delims=" %%a in (filenames.txt) do (
REM here do something inside the loop
REM until all file names from filenames.txt were processed
)
This is designed to find files in c:\work that match a string, and echo the filenames.
#echo off
cd /d "c:\work"
for %%a in ("*string*") do (
echo "%%a"
)

Resources