Forfile command to delete all except a directory - batch-file

I want to use the forfile command to delete all .frm files in some directories. But, I don't want to delete the *.frm files under a specific directory.
I have this, but i don't know how to put the name of the dir where i don't want to delete files:
forfiles /p D:\myfolder\ /s /m *.frm /c "cmd /c IF NOT DESIRE_DIR del #PATH"
Some help, please !

#for /f "delims=" %A in ('dir /ad /b^|findstr /l /v /i "Dirname1 Dirname2"') do #echo %A
This is also a lot quicker than forfiles. Forfiles is only really useful when listing files by date.
Put your folder names in Dirname1, Dirname2 to exclude them. Spaces mean or.
Remember in a batch file %A becomes %%A.
forfiles /p D:\myfolder\ /s /d -7 /m *.frm /c "cmd /c echo #path >> %temp%\temp.txt"
for /f "delims=" %A in ('findstr /i /v "list of excluded directories" ^< "%temp%\temp.txt"') do echo %A
Your /m was also in the wrong place and you would have seen a message telling you that.

Related

Batch Delete excluding files under specific folder (or file names with specific pattern /wildcard e.g. Test123.csv, Test623.csv, Test854.csv)

FORFILES /P "C:\Temp\" /D -3 /S /C "cmd /c if #isdir==FALSE del /F /Q #path"
above script is working fine and delete all files under Temp and its subdirectory older than 3 days.
I want to exclude all files from specific folder say all files from folder XYZ or full path-> C:\Temp\ABC\XYZ
Note : all files under XYZ folders are having pattern say Test*.*.csv
forfiles does not have an exclude option. You have to use something like findstr /V to exclude the results, but that will not form part of the forfiles command in itself. We simply incorporate a for loop and ecxlude using findstr /V, then delete:
#echo off
for /f "delims=" %%i in ('FORFILES /P "%temp%" /D -3 /S /C "cmd /c if #isdir==FALSE echo #path"^| findstr /VI "C:\Temp\ABC\XYZ"') do del /F /Q "%%~i"

Issue Getting a Mass Name change .bat on a share to add spaces to the new file name

I know someone out there has a nice quick solution for this: I just believe I am missing something. I am slightly new to creating bat files. I have roughly 2,000 files with improper naming on a share drive.
The below bat gets me started but I need to have the new file name include spaces but when I try it gives an invalid syntax command even with the ' " '.
Line 3, 3.MRF, is where it is giving me the syntax error '-' is not a valid command.
#echo
forfiles /S /M "1.PURCHASE*.*" /C "cmd /c rename "1.PURCHASE*.*" "2.PURCHASE*.*""
forfiles /S /M "3.MRF*.*" /C "cmd /c rename "3.MRF*.*" "1.MRF - *.*""
forfiles /S /M "3.ACOMRF-*.*" /C "cmd /c rename "3.ACOMRF-*.*" "1.ACO-MRF-*.*""
forfiles /S /M "2.RECEIPT*.*" /C "cmd /c rename "2.RECEIPT*.*" "3.RECEIPT*.*""
forfiles /S /M "2.RECIEPT*.*" /C "cmd /c rename "2.RECIEPT*.*" "3.RECEIPT*.*""
:exit
#pause
Perhaps run a for loop instead, it just looks much better to start off with:
#echo off
for /r /d %%a in (*) do (
pushd "%%~a"
ren "1.PURCHASE*.*" "2.PURCHASE*.*"
ren "3.MRF*.*" "1.MRF - *.*"
ren "3.ACOMRF-*.*" "1.ACO-MRF-*.*"
ren "2.RECEIPT*.*" "3.RECEIPT*.*"
ren "2.RECIEPT*.*" "3.RECEIPT*.*"
popd
)
Here you need one loop that will pushd to each of the subdirectories, rename anything that matches the rename parameter.
I would suggest using String Manipulation within a simple for-loop.
#echo off
setlocal enabledelayedexpansion
FOR %%A IN (3.MRF*.*) DO (
SET name=%%A
rename "!name!" "!name:3.MRF=1.MRF - !"
)
Before:
3.MRF A.txt
3.MRF B.txt
3.MRF C.txt
After:
1.MRF - A.txt
1.MRF - B.txt
1.MRF - C.txt
Update
Made a more generic solution which lets you define all search and replace strings. Moreover it works on all subdirs now.
#echo off
setlocal EnableDelayedExpansion
PUSHD "%0\.."
REM <search_1>;<replace_1|<search_2>;<replace_2>|...|<search_n>;<replace_n>
SET SearchAndReplace=3.MRF - ~1.MRF - ;3.ACOMRF-~1.ACO-MRF-
REM Replace ; with \n
SET SearchAndReplace=!SearchAndReplace:;=^
!
REM iterate over search and replace tokens
FOR /F "tokens=1,2 delims=~" %%G IN ("!SearchAndReplace!") DO (
set search=%%G
set replace=%%H
FOR /F "usebackq delims=" %%I IN (`dir /S /B /A:-d "*!search!*" 2^>nul`) do (
set file="%%I"
REM hack to allow replace !replace! for !search! in !file!
FOR /F "delims=" %%J IN ("!search!") do (
FOR /F "delims=" %%K IN ("!replace!") do (
echo move !file! !file:%%J=%%K!
move !file! !file:%%J=%%K!
)
)
)
)
POPD
Set the SearchAndReplace variable as needed (see comment).

How to I delete from all Sub Directories apart from a select few

I would like to create 1 batch file that deletes a type of file (i.e. ".bak") with different date ranges situated in different sub folders that are in the same patent folder, but I can list the minority of folders.
I have managed to create a FOR loop to look in certain directories (which the directories are set in a variable), deleting any '*.bak' file over a certain age with the below script:
SET "WeeklyBAKLocation=Folder20 Folder21 Folder25 Folder28"
SET WeeklyBAK=7
SET DailyBAK=3
FOR %%x IN (%WeeklyBAKLocation%) DO forfiles /p "%%x" /s /m *.bak /d -%WeeklyBAK% /c "cmd /c DEL #path /q"
<SECOND FOR LOOP below HERE>
The above works deleting .bak files older than 7 days in those folders, my question is how can I reverse that and delete '.bak' files in every other directory that's older than 3 days, without deleting the ones kept from the first query?
I tried nesting FOR and FORFILES, using findstr /v to ignore them as below (but it would ignore each directory for that 1 loop, and then delete it for the next loop wouldn't it, so eventually it would not have worked and is massively inefficient?)
SET "WeeklyBAKLocation=Folder20 Folder21 Folder25 Folder28"
SET WeeklyBAK=7
SET DailyBAK=3
<First FOR LOOP above HERE>
FOR %%x IN (%WeeklyBAKLocation%) DO FOR /F "delims=*" %%G IN ('dir /b /s "%~dp0" ^| findstr /v "\%%x"') DO forfiles /p "%%G" /s /m *.bak /d -%DailyBAK% /c "cmd /c ECHO #path /q"
Essentially can I ignore SOME directories at once when walking through them to find .bak files to delete only ones that are 3 days old.
Many thanks in advance.
FOR /F "delims=*" %%G IN (
'dir /b /s /AD "%~dp0" ^| findstr /v "\%%x"') DO (
set "zapme=Y"
FOR %%x IN (%WeeklyBAKLocation%) DO if /i "%%x"=="%%G" set "zapme="
if defined zapme forfiles /p "%%G" /s /m *.bak /d -%DailyBAK% /c "cmd /c ECHO #path /q"
)
read the directory list in basic form (note /ad) and for each directory, set zapme to something then check whether the directory is not to be processed and set zapme to nothing if it's one of those directories. The zapme flag can then be tested for being set or not set. If it's set, go ahead and process the directory.
FOR /F "delims=*" %%G IN (
'dir /b /AD "%sourcedir%"') DO (
set "zapme=Y"
FOR %%x IN (%WeeklyBAKLocation%) DO if /i "%%x"=="%%G" set "zapme="
if defined zapme ECHO forfiles /p "%sourcedir%\%%G" /s /m *.bak /d -%DailyBAK% /c "cmd /c ECHO #path /q"
)
...happens every time I don't actually test it...

forfiles command ignore a directory

I want to write a batch that finds all docs less than 50 mb in c:\ and copy them in a folder but ignore system directory docs. I prefer it does not even search in the system dir.
Here is my batch that finds and copies all files less 50 mb in right directory but i can not make it to ignore system from searching or C:\Windows directory.
#ECHO off
:: variables
SET odrive=%odrive:~0,2%
SET backupcmd=xcopy /s /c /d /e /h /i /r /y
MKDIR "C:\Users\Documents\USBBackups\DOC\C"
forfiles /P C:\ /M *.DOC* /S /C "cmd /c if #fsize leq 50000000 echo #PATH " > "C:\Users\Documents\USBBackups\DOCC.txt"
FOR /F "tokens=*" %%a in (C:\Users\Documents\USBBackups\DOCC.txt) do xcopy %%a "C:\Users\Documents\USBBackups\DOC\C" /c /h /i /r /y
#ECHO off
There is no way to tell forfiles to exclude certain directories when switch /S is provided. You will have to write your own code that does that.
I would not use forfiles for that due to poor performance, but standard for instead:
#echo off
for /D %%D in ("%SystemDrive%\*.*") do (
if /I not "%%D"=="%SystemRoot%" (
pushd "%%D"
for /R %%F in ("*.doc?") do (
if %%~zF LEQ 50000000 (
echo %%F
)
)
popd
)
)
Here the root directory level is enumerated by for /D. All directories other than %SystemRoot% are enumerated recursively by for /R.
I changed the search pattern from *.doc* to *.doc? in order not to include files ending in .doc.lnk for example, which I guess you do not want to be retrieved.
Instead of the echo command you can directly place your xcopy command line with "%%F" provided as the copy source.
You can do the same directly in command prompt as a one-liner, like this:
for /D %D in ("%SystemDrive%\*.*") do #if /I not "%D"=="%SystemRoot%" pushd "%D" & (for /R %F in ("*.doc?") do #if %~zF LEQ 50000000 echo %F) & popd
I recommend not to walk through the entire directory tree and later filtering by something like findstr /V /I /L /B /C:"%SystemRoot%", because in that case you were wasting time enumerating a huge number of items which you ignore afterwards.
However, if you do want to rely on forfiles /S, the working command line looks like this:
2> nul forfiles /S /P "C:\\" /M "*.doc*" /C "cmd /C if #isdir==FALSE if #fsize LEQ 50000000 echo #path" | findstr /V /I /L /B /C:"\"%SystemRoot%"
Adapt this technique of using findstr to filter out certain names.
To see size of folders in Documents, excluding music, video, or pictures folders.
for /f "skip=3 tokens=3" %A in ('Reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v "Personal"') do set doc=%A
for /f "usebackq tokens=2* delims= " %i IN (`dir "%doc%" /a /s ^|findstr /i /v "\/"^|findstr /l /v "Pictures Music Video"`) DO #echo %j&echo.
However you could start the forfiles command in the c:\users or the particular users home folder (%userprofile%). You specify to start at c:\ which includes all folders.
forfiles /P %userprofile% /M .DOC /S /C "cmd /c if #fsize leq 50000000 echo #PATH "
forfiles /P c:\users /M .DOC /S /C "cmd /c if #fsize leq 50000000 echo #PATH "

spaces in for /f forfiles batch not working

I'm trying to make an automated old file deleting script, this is what I've come up with so far.
First I make an input file for user home dirs.
Command:
dir downloads /s /b echo > input.txt
It fills the .txt file like this:
F:\HomeDirs\a.Durge\Mijn Documenten\Downloads
F:\HomeDirs\a.eimers\Mijn Documenten\Downloads
F:\HomeDirs\a.eimers\system\Downloads
F:\HomeDirs\a.gacem\system\Downloads
After the input file has completed to fill up i want this as input to delete files older than 30 days in folders named downloads
FOR /f %%G in (input.txt) DO forfiles /p %%G /C "cmd /c del %%G\*.* /q" /D -30
This works to a certain extent, the filepaths that contain spaces aren't affected proccessed.
I tried adding quotes around the paths but I think I'm goofing up somewhere.
This is the error the batch gives me:
D:\Scripts>forfiles /p "F:\HomeDirs\a.Durge\Mijn /C "cmd /c del "F:\HomeDirs\a.Durge\Mijn\*.* /q" /D -30
ERROR: Invalid argument/option - 'F:\HomeDirs\a.Durge\Mijn\*.* /q'.
Type "FORFILES /?" for usage.
Filepaths that dont contain the spaces are processed properly.
How can I resolve this?
Your for /f command is using space as a delimiter (space and tab are the default delimiters).
So F:\HomeDirs\a.Durge\Mijn Documenten\Downloads will return two tokens.
F:\HomeDirs\a.Durge\Mijn
Documenten\Downloads
To stop this happening add "delims=" (use no delimiters at all) to your command:
FOR /f "delims=" %%G in (input.txt) DO forfiles /p %%G /C "cmd /c del %%G\*.* /q" /D -30
You can further simplify things by using a different type of for which loops against the output of another command (removing the need for an intermediate file), combining both commands in one line:
FOR /f "delims=" %%G in ('dir downloads /s /b') DO forfiles /p %%G /C "cmd /c del %%G\*.* /q" /D -30
See FOR /F Loop command: against the results of another command. for more information.
Put quotes around %%G.
FOR /f %%G in (input.txt) DO forfiles /p "%%G" /C "cmd /c del %%G\*.* /q" /D -30
Put "tokens=*" in the "for /f"
For /f "tokens=*"
So you get the whole line not just the first "token" up to the space

Resources