spaces in for /f forfiles batch not working - batch-file

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

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).

Delete all files including files with spaces BATCH

I'm looking for a way to delete all files in a directory that are older than x days and that are not of certain extension, I found this command line for the first:
forfiles -p "C:\Test" -s -m *.* /D -5 /C "cmd /c del #path"
and this for the second:
for /f %%F in ('dir /b /a-d ^| findstr /vile ".bat"') do del "%%F"
but could not do them in one command line, and for the second it ignores files containing spaces in their names.
Note that I am doing this in batch files (DeleteOldFiles.bat).
Thanks to everyone in advance.
The FORFILES command does have an option to see what the file extension is. So all you have to do is use that variable to compare it with the extension you are trying to exclude.
forfiles -p "C:\Test" -s -m *.* /D -5 /C "cmd /c if /I not #ext==0x22bat0x22 del #path"
The 0x22 is the hex representation of the double quote. Forfiles variables are always quoted.
When using a for loop with /f certain special characters are default delimeters. One of those being a space, so a name with a space will be split by space. So we need to ad "delims=" to override default delims.
I however suspect that you want to run both deletion of old files and excluding certain bat extensions purely because you batch file might be in the sam directory as the files you want to delete. You can overcome this simply by placing the file elsewhere and specifying path to the directory where files needs deleting. If so then simply add this to the batch file and place the file in a seperate dir:
forfiles -p "C:\Test" -s -m *.* /D -5 /C "cmd /c del #path"
If you want to delete all other files from a dir which containsa batch files and seperately delete files older than N date in another then these will do.
Batch file version:
#echo off
forfiles -p "C:\Test" -s -m *.* /D -5 /C "cmd /c del #path"
for /f "delims=" %%F in ('dir /b /a-d ^| findstr /vile ".bat"') do echo del "%%F"
pause
Cmdline version:
forfiles -p "C:\Test" -s -m *.* /D -5 /C "cmd /c del #path" & for /f "delims=" %%F in ('dir /b /a-d ^| findstr /vile ".bat"') do echo del "%%F"
Be careful though where you place the batch file as there is no specific path in the command for the for loop. For that very reason, I placed echo before del once you are sure that your query echo's the result you expect, you can remove the echo to perform the actual task.

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 "

Forfile command to delete all except a directory

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.

Resources