This question already has answers here:
FORFILES date -after- (date calc in cmd file)
(2 answers)
Closed 1 year ago.
This finds no files (two in the directory are only one day old):
for /d %%d in (%mydir%\*) do (
cd %%d
forfiles /P %%d /M *.ppt* /D +7 /C "cmd /c echo Converting #file"
)
When I change the /D parameter to /D -6 it's ok,
also /D 25.10.2021 is ok.
But /D +7 never finds any file.
Is it a bug or feature?
Here's an example which is an adaption of what looks like the same method shown in aschipfl's answer within the link in their comment.
#Set "MyDir=%UserProfile%\Videos"
#For /F "Delims=" %%G In ('Dir "%MyDir%" /B /A:D 2^>NUL') Do #For /F "Delims=" %%H In ('^"Dir /B /A:-D 1^>NUL 2^>^&1 ^&^& %SystemRoot%\System32\forfiles.exe /P "%MyDir%\%%G" /D -0 /C "%SystemRoot%\System32\cmd.exe /D /C 0x22If #IsDir==FALSE %SystemRoot%\System32\forfiles.exe /M #File /D -8 1>NUL 2>&1 || Echo #Path0x22" 2^>NUL^"') Do #Echo Converting %%H
#Pause
I have left out any explanation, as the answer linked above, explains the methodology, this essentially wraps that methodology within a For /F loop.
Related
This is a sample code that allows me to delete all folders with the name ".RemoveAsap" attached to them
#echo on
set dir="\\TestPC2\c$\Users"
FOR /D /R %dir% %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
pause
exit
Simply running the code as is runs perfectly but when I try to make the code more interactive, I get the error
#echo on
cd C:\Users\User1\Desktop\Test\
TYPE con >> LowDASD.txt
For /F %%A in (LowDASD.txt) do echo "\\%%A\c$\users\" >> LowDASD2.txt
set "LwDs"="LowDASD2.txt"
FOR /D /R "%LwDs%" %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
pause
LowDASD2.txt would be the address/ directory location where the directories will be deleted, IE \\TestPC2\c$\Users
The code does not delete anything or give an error that "the path is too long" at least it was doing that with the previous variations that I was trying. If someone can help me with this, i would greatly appreciate it.
Try using FORFILES, instead of the command FOR, this way you can make it work like this:
:: forfiles /p "folder_location" 'args' '/c "cmd /c del /f /q #path"'
:: So...
cd C:\Users\User1\Desktop\Test\
TYPE con >> LowDASD.txt
For /F %%A in (LowDASD.txt) do echo "\\%%A\c$\users\" >> LowDASD2.txt
set "LwDs=LowDASD2.txt"
forfiles /p %LwDs% /s /c "cmd /c del /f /q #path"
:: You can use '/d -90' to delete files older than 90 days in the folder
FOR /D /R "%LwDs%" %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
Simply will not work, as %LwDs% is a filename.
FOR /F "usebackq delims=" %%j in ("%LwDs%") do FOR /D /R "%%j" %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
You would think might work - %%j being assigned to each entry in the %LwDs% file in turn; usebackq used because the filename is "quoted" (see for /? from the prompt for documentation)
But it doesn't - the for /d /r syntax doesn't accept metavariables...
So - try
FOR /F "usebackq delims=" %%j in ("%LwDs%") do set "target=%%j"&call :expunge
Where expunge is an internal subroutine. The colon is required
:expunge
echo target="%target%"
FOR /d /r "%target%" %%X IN (*.RemoveAsap) DO echo RMDIR /S /Q "%%X"
echo ====================
goto :eof
An internal subroutine should be placed after an unconditional goto, which should in your case follow the pause
pause
goto :eof
Where :eof (compulsory colon again) is defined as the physical end-of-file and should not be used as a user-label. Reaching physical end-of-file returns from a call.
Always verify against a test directory before applying to real data.
Note that the rmdir is merely being echoed for testing purposes - remove the echo keyword after testing to activate.
=== Extension
The full code should thus be
#echo on
set dir="\\TestPC2\c$\Users"
FOR /F "usebackq delims=" %%j in ("%LwDs%") do set "target=%%j"&call :expunge
pause
exit
:expunge
echo target="%target%"
FOR /d /r "%target%" %%X IN (*.RemoveAsap) DO echo RMDIR /S /Q "%%X"
echo ====================
goto :eof
ECHO ===FILES TO TRANSFER===
FOR /f "usebackq tokens=*" %%G IN (`DIR /B /S "%~dp0Files"`) DO #ECHO %%G
The output is the full path of the file/dir but I want to make it simpler by removing %~dp0's path from the output
This is the methodology I'd suggest you incorporate, which protects filenames which may include ! characters and limits the output to files, as per your stated requirement:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F Delims^=^ EOL^= %%G In ('Dir /B/S/A-D "%~dp0Files" 2^>NUL')Do (
Set "_=%%G" & SetLocal EnableDelayedExpansion
Echo(!_:*%~dp0Files=.! & EndLocal)
Pause
If you'd prefer not to have a relative path type output then change !_:*%~dp0Files=.! to !_:*%~dp0Files\=!
Alternatively, you could grab the relative paths using the slower, forfiles.exe utility:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE Echo #RelPath"
If you prefer it without doublequotes then this modification should do that:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE For %%G In (#RelPath)Do Echo %%~G"
And if you wanted it without the leading .\ then perhaps:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE For /F 0x22Tokens=1*Delims=\0x22 %%G In (#RelPath)Do Echo %%H"
You could also do this by leveraging powershell.exe:
%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoProfile Get-ChildItem -Path "%~dp0Files" -File -Force -Name -Recurse
which could possibly be done, (not recommended), in as short a line as:
powershell -NoP ls "%~dp0Files" -File -Fo -Na -Rec
just remove %~dp0 from each entry (Note: that doesn't work with %%G metavariables, you have to use a "normal" environment variable):
#echo off
setlocal enabledelayedexpansion
ECHO ===FILES TO TRANSFER===
FOR /f "usebackq tokens=*" %%G IN (`DIR /B /S "%~dp0"`) DO (
set "file=%%G"
echo !file:%~dp0=!
)
To retrieve the relative path to a given root without string manipulation, you could use the xcopy command with its /L option, which lists relative paths to files it would copy without /L:
pushd "%~dp0" && (
for /F "delims= eol=|" %%G in ('xcopy /L /S /Y /I "Files" "%TEMP%" ^| find "\"') do (
echo(%%G
)
popd
)
pushd and popd are used to change into and return from the root directory, respectively.
The find command is used to suppress xcopy's summary line # File(s).
I have a batch file that works on my local machine (Windows 7), but doesn't fully work on the server it is intended to live on(Windows 2008 R2 Service Pack 1).
It needs to delete files older than a specified number of days in all listed folders, then delete empty folders and sub-folders.
Script:
set DaysOld=3
set "folders[0]=C:\Test\BatchDel\1"
set "folders[1]=C:\Test\BatchDel\2"
set "folders[2]=C:\Test\BatchDel\3"
set "folders[3]=C:\Test\BatchDel\DNE"
for /F "tokens=1* delims==" %%s in ('set folders[') do (
forfiles /p "%%t" /s /m * /D -%DaysOld% /C "cmd /c del #path"
)
for /f "delims=" %%d in ('dir /ad/b/s ^| sort /R') do rd "%%d"
pause
When run on my local machine (spacing added):
C:\Test\BatchDel>set DaysOld=3
C:\Test\BatchDel>set "folders[0]=C:\Test\BatchDel\1"
C:\Test\BatchDel>set "folders[1]=C:\Test\BatchDel\2"
C:\Test\BatchDel>set "folders[2]=C:\Test\BatchDel\3"
C:\Test\BatchDel>set "folders[3]=C:\Test\BatchDel\DNE"
C:\Test\BatchDel>for /F "tokens=1* delims==" %s in ('set folders[') do (forfiles /p "%t" /s /m * /D -3 /C "cmd /c del #path" )
C:\Test\BatchDel>(forfiles /p "C:\Test\BatchDel\1" /s /m * /D -3 /C "cmd /c del#path" )
ERROR: No files found with the specified search criteria.
C:\Test\BatchDel>(forfiles /p "C:\Test\BatchDel\2" /s /m * /D -3 /C "cmd /c del#path" )
ERROR: No files found with the specified search criteria.
C:\Test\BatchDel>(forfiles /p "C:\Test\BatchDel\3" /s /m * /D -3 /C "cmd /c del#path" )
ERROR: No files found with the specified search criteria.
C:\Test\BatchDel>(forfiles /p "C:\Test\BatchDel\DNE" /s /m * /D -3 /C "cmd /c del #path" )
ERROR: The specified directory does not exist.
C:\Test\BatchDel>for /F "delims=" %d in ('dir /ad/b/s | sort /R') do rd "%d"
C:\Test\BatchDel>rd "C:\Test\BatchDel\3"
C:\Test\BatchDel>rd "C:\Test\BatchDel\2"
C:\Test\BatchDel>rd "C:\Test\BatchDel\1"
The directory is not empty.
C:\Test\BatchDel>pause
Press any key to continue . . .
When I run it on the server it asks for permission to delete each folder. (spacing added).
F:\data\Scripts>set DaysOld=5
F:\data\Scripts>set "folders[0]=F:\data\Environments\TestA\Cache_Data"
F:\data\Scripts>set "folders[1]=F:\data\Environments\TestB\Cache_Data"
F:\data\Scripts>for /F "tokens=1* delims==" %s in ('set folders[') do (forfiles /p "%t" /s /m * /D -5 /C "cmd /c del #path" )
F:\data\Scripts>(forfiles /p "F:\data\Environments\TestA\Cache_Data" /s /m * /D -5 /C "cmd /c del #path" )
F:\data\Environments\TestA\Cache_Data\0432f59d-9fd1-46ed-8579-9ebe358113fb\*, Are you sure (Y/N)?
I need it to delete the empty folders on the server without pressing Y for each one.
EDIT:
I updated the script. Thanks aschipfl! it is now closer to working. It is now asking Y/N to delete each folder.
EDIT 2: updated the outputs.
I found this solution:
for /F "tokens=1* delims==" %%s in ('set folders[') do (
forfiles /p "%%t" /s /m *.* /D -%DaysOld% /C "cmd /c del #path"
for /f "delims=" %%d in ('dir "%%t" /s /b /ad ^| sort /r') do rd "%%d"
)
I want to get the number of files modified before 10 days to a variable.
I can get number of files using
forfiles /P "D:\files" /S /D -10 | find /c /v ""
But when i try to assign it to a variable using FOR it gives error.
Command I used in FOR is
FOR /F "delims=" %i IN ('forfiles /P "D:\files" /S /D -10 | find /c /v ""') DO set today=%i
It actually works fine when I remove | find /c /v ""
FOR /F "delims=" %i IN ('forfiles /P "D:\files" /S /D -10 ^| find /c /v ""') DO set today=%i
in this case you need to escape the pipe.
Yes you can use the FIND command to count how many occurrences it finds but you don't need to. You could just use the set command to iterate a variable.
FOR /F "delims=" %%G IN ('forfiles /P "D:\files" /S /D -10') do #set /a count+=1
i'm a newbie in batch scripting,started learning this from last week only and this is the first question that i'm asking here.here is my situation,
Consider this example,this lists all directories under D:/Jose/test1 and append this to a text file.
Code:
#echo off
SETLOCAL EnableDelayedExpansion
cd /d D:\Jose\test1
FOR /F "delims=" %%G in ('dir /ad /on /s /b') DO (
ECHO %%~pG%%~nG>>D:\test2\list.txt
)
ENDLOCAL
pause
Text file output :
\Jose\test1\1
\Jose\test1\2
\Jose\test1\1\12
\Jose\test1\1\13
\Jose\test1\1\12\131
\Jose\test1\1\12\Copy of 131
\Jose\test1\1\12\131\1311
\Jose\test1\1\12\131\1311\13111
\Jose\test1\1\12\131\1311\13112
\Jose\test1\1\12\Copy of 131\1311
\Jose\test1\1\12\Copy of 131\1311\13111
\Jose\test1\1\12\Copy of 131\1311\13112
\Jose\test1\1\13\132
\Jose\test1\1\13\132\1321
\Jose\test1\1\13\132\1321\13211
I want to remove '\jose' from all line ie, i want to set '\test1' as the starting path. Need help guys..Thanks in advance...
try it with sed for Windows:
for /d /r %%G in (*) do sed -r "s/^\\[^\]+(\\.*)/\1/" "%%~pnxG">>D:\test2\list.txt
..solution with pure batch:
#echo off &setlocal
(FOR /f "tokens=2* delims=\" %%a IN ('dir /ad /on /s /b') DO ECHO(\%%~b)>D:\test2\list.txt
TYPE D:\test2\list.txt
PAUSE
..and more batch:
#echo off &setlocal
(FOR /d /r %%G in (*) DO (
SET "fname=%%~G"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "fname=!fname:*\Jose=!"
ECHO(!fname!
ENDLOCAL
))>D:\test2\list.txt
TYPE D:\test2\list.txt
PAUSE