Пакетний файл для видалення файлів старше N днів


678

Я шукаю спосіб видалити всі файли старше 7 днів у пакетному файлі. Я здійснив пошук в Інтернеті і знайшов кілька прикладів із сотнями рядків коду та інші, для виконання яких потрібно встановити додаткові утиліти командного рядка.

Подібні речі можна зробити в BASH всього за пару рядків коду. Здається, що щось, принаймні віддалено легко, можна зробити для пакетних файлів у Windows. Я шукаю рішення, яке працює в стандартному командному рядку Windows, без зайвих утиліт. Будь ласка, не PowerShell чи Cygwin.


8
Джефф Етвуд відповів на це на Serverfault, що, на мою думку, тут слід зафіксувати. serverfault.com/questions/49614/delete-files-older-than-x-days
Dusty

Новий метод , заснований в файлі .BAT , які використовують внутрішні команди CMD.exe тільки був розміщений тут: stackoverflow.com/questions/9746778 / ...
Aacini

1
gehrcke.de/timegaps був розроблений для цієї мети. Це навіть дозволяє створити більш складну схему видалення: крім зберігання файлів останніх 7 днів, вона, наприклад, дозволяє також зберігати один файл за кожен останній 8 тижнів, 12, місяців, 2 роки.
Д-р Ян-Філіп Геркк

Відповіді:


1071

Насолоджуйтесь:

forfiles -p "C:\what\ever" -s -m *.* -d <number of days> -c "cmd /c del @path"

Детальнішу інформацію див. У forfilesдокументації .

Щоб отримати більше смаку, зверніться до індексу AZ командного рядка Windows XP .

Якщо на вашому пристрої не forfilesвстановлено, скопіюйте його з будь-якого Windows Server 2003 на комп'ютер Windows XP за адресою %WinDir%\system32\. Це можливо, оскільки EXE повністю сумісний між Windows Server 2003 та Windows XP.

Пізніші версії Windows та Windows Server встановили його за замовчуванням.

Для Windows 7 та новіших версій (включаючи Windows 10):

Синтаксис трохи змінився. Тому оновлена ​​команда:

forfiles /p "C:\what\ever" /s /m *.* /D -<number of days> /C "cmd /c del @path"

12
Має бути del @FILE, питання справи. Також я пропоную використовувати / c echo @FILE для тестування
Рассел Стін,

40
@Russell: @PATH - це повний шлях, включаючи ім'я. @FILE - це лише ім'я, тому якщо ви маєте справу з папками, це не працюватиме.
gregmac

86
Зауважте, що якщо ви хочете, щоб файли були СТАРІшими, ніж 10 днів, вам потрібно вказати -d "-10". -ve означає "старший за", + ve означає "новіший за". Ви також можете вказати формат DDMMYY або -DDMMYY як параметр -d.
gregmac

42
Я використав цей синтаксис на Win Server 2008: forfiles / P "C: \ Mysql_backup" / S / M * .sql / D -30 / C "cmd / c del @PATH"
jman

9
Ця відповідь спрацьовує, коли "старше 7 днів" визначається як "змінено більше 7 днів тому", а не "створено більше 7 днів тому". Як останнього можна досягти?
TimS

76

Виконайте такі команди :

ROBOCOPY C:\source C:\destination /mov /minage:7
del C:\destination /q

Перемістіть усі файли (використовуючи / mov, який переміщує файли, а потім видаляє їх на відміну від / переміщення, яке переміщує цілі файли, які потім видаляються) через робочу копію в інше місце, а потім виконайте команду видалення на цьому шляху, і ви всі добре.

Крім того, якщо у вас є каталог з великою кількістю даних, ви можете використовувати /mirперемикач


5
Здебільшого це досить непрактична відповідь. Якщо у мене є каталог з великою кількістю даних у ньому, там не буде добре. Я б пішов з однією з відповідей, яка робить це "на місці"
adamb0mb

5
@ adamb0mb це жодним чином непрактично - якщо "призначення" знаходиться в тій же файловій системі, що і "джерело" , операція переміщення є досить легкою. Оскільки роботокопія дійсно надійна, вона насправді буде працювати для будь-якого розміру каталогу, незрозумілих імен файлів, в основному довільної довжини шляху і включати каталоги, якщо вам це потрібно - те, що точно не можна сказати про багато інших утиліт Windows. Я б використовував rd /s /q c:\destinationзамість delкоманди, хоча і навіть використовував інший robocopy /mir c:\emptydir c:\destinationзапуск для очищення каталогу, якщо ви очікуєте проблем з іменами файлів.
syneticon-dj

12
Крім того, робокопія підтримує UNC-шляхи - що forfilesз прийнятої відповіді не зробить.
syneticon-dj

3
Мої думки були більш узгоджені: "Мої файли вже там, де я їх хочу. Я не хочу їх переміщувати". "Видалення файлів логічно те, що ви робите, тому робіть це. Не перевантажуйте Robocopy, щоб це зробити"
adamb0mb

3
Я рекомендую цей одношаровий перегляд для перегляду всіх файлів C:\testстарше 7 днів. Щоб видалити файли, змініть echoна del:forfiles /p "C:\test" /m "*.*" /c "cmd /c echo @file" /D -7
PowerUser

25

Добре набридло, і я придумав це, що містить мою версію замінника епохи Linux у бідного чоловіка, обмежену для щоденного використання (не затримка часу):

7daysclean.cmd

@echo off
setlocal ENABLEDELAYEDEXPANSION
set day=86400
set /a year=day*365
set /a strip=day*7
set dSource=C:\temp

call :epoch %date%
set /a slice=epoch-strip

for /f "delims=" %%f in ('dir /a-d-h-s /b /s %dSource%') do (
    call :epoch %%~tf
    if !epoch! LEQ %slice% (echo DELETE %%f ^(%%~tf^)) ELSE echo keep %%f ^(%%~tf^)
)
exit /b 0

rem Args[1]: Year-Month-Day
:epoch
    setlocal ENABLEDELAYEDEXPANSION
    for /f "tokens=1,2,3 delims=-" %%d in ('echo %1') do set Years=%%d& set Months=%%e& set Days=%%f
    if "!Months:~0,1!"=="0" set Months=!Months:~1,1!
    if "!Days:~0,1!"=="0" set Days=!Days:~1,1!
    set /a Days=Days*day
    set /a _months=0
    set i=1&& for %%m in (31 28 31 30 31 30 31 31 30 31 30 31) do if !i! LSS !Months! (set /a _months=!_months! + %%m*day&& set /a i+=1)
    set /a Months=!_months!
    set /a Years=(Years-1970)*year
    set /a Epoch=Years+Months+Days
    endlocal& set Epoch=%Epoch%
    exit /b 0

ВИКОРИСТАННЯ

set /a strip=day*7: Змініть 7 на кількість днів, які потрібно зберегти.

set dSource=C:\temp : Це початковий каталог для перевірки наявності файлів.

ПРИМІТКИ

Це неруйнівний код, він відображатиме, що б сталося.

Змінити:

if !epoch! LEQ %slice% (echo DELETE %%f ^(%%~tf^)) ELSE echo keep %%f ^(%%~tf^)

до чогось типу:

if !epoch! LEQ %slice% del /f %%f

тому файли фактично видаляються

Лютий : важко кодирується до 28 днів. Біссексуальні роки - справді пекло. якщо хтось має ідею, яка не додала б 10 рядків коду, продовжуйте публікацію, щоб я додав його до свого коду.

епоха : я не брав до уваги час, оскільки потрібно видалити файли, старші за певну дату, час, який займає години / хвилини, видалив би файли з дня, призначеного для зберігання.

ОБМЕЖЕННЯ

епоха сприймається як ваш короткий формат дати - РРРР-ММ-DD. Його потрібно адаптувати для інших налаштувань або оцінки часу виконання (прочитати sShortTime, конфігурацію, пов'язану з користувачем, налаштувати правильний порядок поля у фільтрі та використовувати фільтр для вилучення правильних даних з аргументу).

Я згадав, що ненавиджу автоматичне форматування цього редактора? це видаляє порожні рядки, а копіювальна паста - пекло.

Я сподіваюся, що це допомагає.


4
+1 для неруйнівного коду, я спробую це врахувати, коли я сам надаю приклади коду.
Haugholt

5
Шлях пізно і абсолютно не пов'язаний, але 7daysclean.cmdзвучить як дивовижна назва групи Synth-Punk.
Флонк

21
forfiles /p "v:" /s /m *.* /d -3 /c "cmd /c del @path"

Ви повинні зробити /d -3(на 3 дні раніше) Це добре для мене. Тож усі складні партії могли бути у відро для сміття. Також forfilesне підтримуйте UNC-шляхи, тому встановіть мережеве підключення до певного диска.


3
Та сама помилка, що і в інших відповідях (включаючи прийняту). Звідки взялася ця дивна звичка уточнювати *.*? Wildcard *.*не відповідає всім файлам у Windows. Він відповідає лише файлам .у своїх іменах. ОП ніколи нічого не говорив про те, щоб вимагати .ім'я файлу. Правильний параметр є /M *, але це все одно за замовчуванням. У цьому немає потреби /Mвзагалі.
ANT

@AnT: Ви впевнені? Я думаю, що *.*поводиться точно так, як *у Windows. Насправді я просто спробував це на своєму комп’ютері і dir *.*справді в списку test file- файл без розширення.
Андреас Рейбранд

1
@Andreas Rejbrand: Я також вважаю, що це дивно, але лікування *.*невідповідне між, скажімо, dirі -mваріантом forfiles. -m *.*Маска дійсно пропустити extensionless імена файлів, як я вже говорив в моєму коментарі вище (спробуйте самі). Найцікавішим тут є те, що документація на MS чітко зазначає, що -m *.*це за замовчуванням. Однак якщо ви спробуєте це в реальному житті, ви побачите, що за замовчуванням насправді -m *- всі файли повторені.
1818 року

1
Ця сторінка MS-документації - technet.microsoft.com/en-us/library/cc753551(v=ws.11).aspx - містить велику кількість помилок (наприклад, у прикладах), оскільки автор документа неправильно вважав, що *.*маска застосована до всіх файлів. Моє реторичне запитання про "цю дивну звичку" справді не вимагалося, оскільки трактувати *.*і *як рівнозначно - це давня умова Windows. Тим НЕ менше, /mваріант в forfilesтрапляється , що порушує конвенцію з якої - то причини.
ANT

1
Фон на 5 макетів
MSalters

18

Подивіться на мою відповідь на подібне запитання :

REM del_old.bat
REM usage: del_old MM-DD-YYY
for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do if exist %%~nxa echo %%~nxa >> FILES_TO_KEEP.TXT
for /f "tokens=*" %%a IN ('xcopy *.* /L /I /EXCLUDE:FILES_TO_KEEP.TXT null') do if exist "%%~nxa" del "%%~nxa"

Це видаляє файли, старіші за вказану дату. Я впевнений, що його можна змінити, щоб повернутися на сім днів із поточної дати.

оновлення: Я помічаю, що HerbCSO покращився на вищезгаданому сценарії. Рекомендую натомість використовувати його версію .


12

Моя команда

forfiles -p "d:\logs" -s -m*.log -d-15 -c"cmd /c del @PATH\@FILE" 

@PATH - це лише шлях у моєму випадку, тому мені довелося скористатися @PATH\@FILE

теж forfiles /?не працював для мене, але forfiles(без "?") працював чудово.

І єдине питання у мене: як додати кілька масок (наприклад, " .log | .bak")?

Все це стосується forfiles.exe, який я завантажив тут (у програмі win XP)

Але якщо ви використовуєте сервер Windows forfiles.exe, він вже має бути, і він відрізняється від ftp-версії. Ось чому я повинен змінити команду.

Для Windows Server 2003 я використовую цю команду:

forfiles -p "d:\Backup" -s -m *.log -d -15 -c "cmd /c del @PATH"

9

Дуже часто виникають відносні питання, пов’язані з датою / часом, за допомогою пакетного файлу. Але інтерпретатор командного рядка cmd.exe не має функції для обчислення дати та часу. Тут вже розміщено багато хороших робочих рішень із застосуванням додаткових консольних додатків чи сценаріїв, на інших сторінках Stack Overflow та на інших веб-сайтах.

Загальним для операцій на основі дати / часу є вимога перетворення рядка дати / часу в секунди з визначеного дня. Дуже часто зустрічається 1970-01-01 00:00:00 UTC. Але будь-який пізній день також може бути використаний залежно від діапазону дат, необхідного для підтримки конкретного завдання.

Jay розмістив 7daysclean.cmd, що містить швидке рішення "дата-секунда" для інтерпретатора командного рядка cmd.exe . Але високосні роки не враховують правильно. JR розмістив надбудову для врахування високосного дня поточного року, але ігноруючи інші високосні роки з базового року, тобто з 1970 року.

Я використовую з 20 років статичні таблиці (масиви), створені один раз з невеликою функцією С, для швидкого отримання кількості днів, включаючи високосні дні з 1970-01-01 в функціях перетворення дати / часу в моїх додатках, написаних на C / C ++.

Цей дуже швидкий метод таблиці може бути використаний також у пакетному коді, використовуючи команду FOR . Тому я вирішив кодувати пакетну підпрограму, GetSecondsяка обчислює кількість секунд з 1970-01-01 00:00:00 UTC для рядка дати / часу, переданого до цієї програми.

Примітка: стрибкові секунди не враховуються, оскільки файлові системи Windows також не підтримують високосні секунди.

По-перше, таблиці:

  1. Дні з 1970-01-01 00:00:00 UTC за кожен рік, включаючи високосні дні.

    1970 - 1979:     0   365   730  1096  1461  1826  2191  2557  2922  3287
    1980 - 1989:  3652  4018  4383  4748  5113  5479  5844  6209  6574  6940
    1990 - 1999:  7305  7670  8035  8401  8766  9131  9496  9862 10227 10592
    2000 - 2009: 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245
    2010 - 2019: 14610 14975 15340 15706 16071 16436 16801 17167 17532 17897
    2020 - 2029: 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550
    2030 - 2039: 21915 22280 22645 23011 23376 23741 24106 24472 24837 25202
    2040 - 2049: 25567 25933 26298 26663 27028 27394 27759 28124 28489 28855
    2050 - 2059: 29220 29585 29950 30316 30681 31046 31411 31777 32142 32507
    2060 - 2069: 32872 33238 33603 33968 34333 34699 35064 35429 35794 36160
    2070 - 2079: 36525 36890 37255 37621 37986 38351 38716 39082 39447 39812
    2080 - 2089: 40177 40543 40908 41273 41638 42004 42369 42734 43099 43465
    2090 - 2099: 43830 44195 44560 44926 45291 45656 46021 46387 46752 47117
    2100 - 2106: 47482 47847 48212 48577 48942 49308 49673
    

    Обчислення секунд за 2039 по 2106 рік з епохою 1970-01-01 можливе лише з використанням непідписаної 32-бітової змінної, тобто неподписаної довгої (або неподписаної int) в C / C ++.

    Але cmd.exe використовує для математичних виразів підписану 32-бітну змінну. Тому максимальне значення становить 2147483647 (0x7FFFFFFF), що становить 2038-01-19 03:14:07.

  2. Інформація про високосний рік (Ні / Так) за 1970 - 2106 роки.

    1970 - 1989: N N Y N N N Y N N N Y N N N Y N N N Y N
    1990 - 2009: N N Y N N N Y N N N Y N N N Y N N N Y N
    2010 - 2029: N N Y N N N Y N N N Y N N N Y N N N Y N
    2030 - 2049: N N Y N N N Y N N N Y N N N Y N N N Y N
    2050 - 2069: N N Y N N N Y N N N Y N N N Y N N N Y N
    2070 - 2089: N N Y N N N Y N N N Y N N N Y N N N Y N
    2090 - 2106: N N Y N N N Y N N N N N N N Y N N
                                     ^ year 2100
    
  3. Кількість днів до першого дня кожного місяця в поточному році.

                       Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    Year with 365 days:  0  31  59  90 120 151 181 212 243 273 304 334
    Year with 366 days:  0  31  60  91 121 152 182 213 244 274 305 335
    

Перетворити дату на кількість секунд з 1970-01-01 досить легко за допомогою цих таблиць.

Увага будь-ласка!

Формат рядків дати та часу залежить від регіону та мовних налаштувань Windows. Розмежувачі та порядок маркерів, присвоєних змінним оточуючим середовищем Day, Monthі Yearспочатку цикл FORGetSeconds повинні бути адаптовані до місцевого формату дати / часу, якщо це необхідно.

Необхідно адаптувати рядок даної змінної середовища, якщо формат дати у змінній середовища DATE відрізняється від формату дати, який використовується командою FOR on %%~tF.

Наприклад, коли %DATE%розширюється на, Sun 02/08/2015а %%~tFрозгортається до 02/08/2015 07:38 PMкоду нижче, можна використовувати зі зміною рядка 4 на:

call :GetSeconds "%DATE:~4% %TIME%"

Це призводить до переходу на підпрограму просто 02/08/2015- рядок дати без 3 букв абревіатури будня та роздільного символу пробілу.

Також для передачі поточної дати у правильному форматі можна використати наступне:

call :GetSeconds "%DATE:~-10% %TIME%"

Тепер останні 10 символів з рядка дати передані у функцію, GetSecondsі тому не має значення, чи рядок дати змінної середовища DATE з або без будня, якщо день і місяць завжди мають 2 цифри у очікуваному порядку, тобто у форматі dd/mm/yyyy чи dd.mm.yyyy.

Ось пакетний код з поясненням коментарів, який тільки виводить, який файл видалити, а який зберегти у C:\Tempдереві папок, див. Код першого циклу FOR .

@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Get seconds since 1970-01-01 for current date and time.
call :GetSeconds "%DATE% %TIME%"
rem Subtract seconds for 7 days from seconds value.
set /A "LastWeek=Seconds-7*86400"

rem For each file in each subdirectory of C:\Temp get last modification date
rem (without seconds -> append second 0) and determine the number of seconds
rem since 1970-01-01 for this date/time. The file can be deleted if seconds
rem value is lower than the value calculated above.

for /F "delims=" %%F in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~tF:0"
    rem if !Seconds! LSS %LastWeek% del /F "%%~fF"
    if !Seconds! LEQ %LastWeek% (
        echo Delete "%%~fF"
    ) else (
        echo Keep   "%%~fF"
    )
)
endlocal
goto :EOF


rem No validation is made for best performance. So make sure that date
rem and hour in string is in a format supported by the code below like
rem MM/DD/YYYY hh:mm:ss or M/D/YYYY h:m:s for English US date/time.

:GetSeconds

rem If there is " AM" or " PM" in time string because of using 12 hour
rem time format, remove those 2 strings and in case of " PM" remember
rem that 12 hours must be added to the hour depending on hour value.

set "DateTime=%~1"
set "Add12Hours=0"
if "%DateTime: AM=%" NEQ "%DateTime%" (
    set "DateTime=%DateTime: AM=%"
) else if "%DateTime: PM=%" NEQ "%DateTime%" (
    set "DateTime=%DateTime: PM=%"
    set "Add12Hours=1"
)

rem Get year, month, day, hour, minute and second from first parameter.

for /F "tokens=1-6 delims=,-./: " %%A in ("%DateTime%") do (
    rem For English US date MM/DD/YYYY or M/D/YYYY
    set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
    rem For German date DD.MM.YYYY or English UK date DD/MM/YYYY
    rem set "Day=%%A" & set "Month=%%B" & set "Year=%%C"
    set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
)
rem echo Date/time is: %Year%-%Month%-%Day% %Hour%:%Minute%:%Second%

rem Remove leading zeros from the date/time values or calculation could be wrong.
if "%Month:~0,1%"  EQU "0" ( if "%Month:~1%"  NEQ "" set "Month=%Month:~1%"   )
if "%Day:~0,1%"    EQU "0" ( if "%Day:~1%"    NEQ "" set "Day=%Day:~1%"       )
if "%Hour:~0,1%"   EQU "0" ( if "%Hour:~1%"   NEQ "" set "Hour=%Hour:~1%"     )
if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" )
if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" set "Second=%Second:~1%" )

rem Add 12 hours for time range 01:00:00 PM to 11:59:59 PM,
rem but keep the hour as is for 12:00:00 PM to 12:59:59 PM.
if "%Add12Hours%" == "1" (
    if %Hour% LSS 12 set /A Hour+=12
)
set "DateTime="
set "Add12Hours="

rem Must use 2 arrays as more than 31 tokens are not supported
rem by command line interpreter cmd.exe respectively command FOR.
set /A "Index1=Year-1979"
set /A "Index2=Index1-30"

if %Index1% LEQ 30 (
    rem Get number of days to year for the years 1980 to 2009.
    for /F "tokens=%Index1% delims= " %%Y in ("3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245") do set "Days=%%Y"
    for /F "tokens=%Index1% delims= " %%L in ("Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N") do set "LeapYear=%%L"
) else (
    rem Get number of days to year for the years 2010 to 2038.
    for /F "tokens=%Index2% delims= " %%Y in ("14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 21915 22280 22645 23011 23376 23741 24106 24472 24837") do set "Days=%%Y"
    for /F "tokens=%Index2% delims= " %%L in ("N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N") do set "LeapYear=%%L"
)

rem Add the days to month in year.
if "%LeapYear%" == "N" (
    for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
) else (
    for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
)

rem Add the complete days in month of year.
set /A "Days+=Day-1"

rem Calculate the seconds which is easy now.
set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"

rem Exit this subroutine
goto :EOF

Для оптимальної продуктивності найкраще буде видалити всі коментарі, тобто всі рядки, що починаються з повтору, після пробілів 0-4.

І масиви можуть бути також меншими, тобто зменшуючи часовий діапазон з 1980-01-01 00:00:00 до 2038-01-19 03:14:07, як зараз підтримується пакетним кодом, наприклад, до 2015-01 -01 до 2019-12-31, оскільки в коді нижче використовується код, який дійсно видаляє файли старше 7 днів у C:\Tempдереві папок.

Далі пакетний код, наведений нижче, оптимізований для формату часу за 24 години.

@echo off
setlocal EnableDelayedExpansion
call :GetSeconds "%DATE:~-10% %TIME%"
set /A "LastWeek=Seconds-7*86400"

for /F "delims=" %%F in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~tF:0"
    if !Seconds! LSS %LastWeek% del /F "%%~fF"
)
endlocal
goto :EOF

:GetSeconds
for /F "tokens=1-6 delims=,-./: " %%A in ("%~1") do (
    set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
    set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
)
if "%Month:~0,1%"  EQU "0" ( if "%Month:~1%"  NEQ "" set "Month=%Month:~1%"   )
if "%Day:~0,1%"    EQU "0" ( if "%Day:~1%"    NEQ "" set "Day=%Day:~1%"       )
if "%Hour:~0,1%"   EQU "0" ( if "%Hour:~1%"   NEQ "" set "Hour=%Hour:~1%"     )
if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" )
if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" set "Second=%Second:~1%" )
set /A "Index=Year-2014"
for /F "tokens=%Index% delims= " %%Y in ("16436 16801 17167 17532 17897") do set "Days=%%Y"
for /F "tokens=%Index% delims= " %%L in ("N Y N N N") do set "LeapYear=%%L"
if "%LeapYear%" == "N" (
    for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
) else (
    for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
)
set /A "Days+=Day-1"
set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"
goto :EOF

Для отримання додаткової інформації про формати дати та часу та порівняння часу файлів у Windows дивіться мою відповідь на тему Дізнайтеся, чи файл старший на 4 години у пакетному файлі з великою кількістю додаткової інформації про час файлу.


9

Скопіюйте цей код і збережіть його як DelOldFiles.vbs.

ВИКОРИСТАННЯ В CMD: cscript //nologo DelOldFiles.vbs 15

15 означає видалити файли, старші 15 днів.

  'copy from here
    Function DeleteOlderFiles(whichfolder)
       Dim fso, f, f1, fc, n, ThresholdDate
       Set fso = CreateObject("Scripting.FileSystemObject")
       Set f = fso.GetFolder(whichfolder)
       Set fc = f.Files
       Set objArgs = WScript.Arguments
       n = 0
       If objArgs.Count=0 Then
           howmuchdaysinpast = 0
       Else
           howmuchdaysinpast = -objArgs(0)
       End If
       ThresholdDate = DateAdd("d", howmuchdaysinpast, Date)   
       For Each f1 in fc
     If f1.DateLastModified<ThresholdDate Then
        Wscript.StdOut.WriteLine f1
        f1.Delete
        n = n + 1    
     End If
       Next
       Wscript.StdOut.WriteLine "Deleted " & n & " file(s)."
    End Function

    If Not WScript.FullName = WScript.Path & "\cscript.exe" Then
      WScript.Echo "USAGE ONLY IN COMMAND PROMPT: cscript DelOldFiles.vbs 15" & vbCrLf & "15 means to delete files older than 15 days in past."
      WScript.Quit 0   
    End If

    DeleteOlderFiles(".")
 'to here

8

Для Windows Server 2008 R2:

forfiles /P c:\sql_backups\ /S /M *.sql /D -90 /C "cmd /c del @PATH"

Це видалить усі .sql файли старше 90 днів.


7

Використовуйте forfiles.

Існують різні версії. Ранні користуються параметрами стилю unix.

Моя версія (для сервера 2000 - зауважте, що немає місця після комутаторів) -

forfiles -p"C:\what\ever" -s -m*.* -d<number of days> -c"cmd /c del @path"

Щоб додати файли до XP, отримайте exe з ftp://ftp.microsoft.com/ResKit/y2kfix/x86/

і додайте його до C: \ WINDOWS \ system32


11
@Kibbee це не однакова відповідь, синтаксис інший. Це була геніальна спроба допомогти. Знаючи дуже мало командного рядка Windows, я витратив години розчарувань, примусивши це працювати. Ключовими бітами інформації для мене було те, що існують різні версії (з різним синтаксисом), і що мені потрібно видалити пробіли. Жодна з цих речей не була включена в початкову відповідь. (Я б прокоментував відповідь, але у мене немає привілеїв
Айдан Евен

Та сама помилка, що і в інших відповідях (включаючи прийняту). Джокер *.*в forfilesне відповідають всім файлам. Він відповідає лише файлам .у своїх іменах (тобто файлах із розширеннями). ОП ніколи нічого не говорив про те, щоб вимагати .ім'я файлу. Правильний параметр є /M *, але це все одно за замовчуванням. У цьому немає потреби /Mвзагалі.
1818 року

7

Для Windows 2012 R2 працює наступне:

    forfiles /p "c:\FOLDERpath" /d -30 /c "cmd /c del @path"

щоб побачити файли, які буде видалено, використовуйте це

    forfiles /p "c:\FOLDERpath" /d -30 /c "cmd /c echo @path @fdate"

Це працює навіть в Windows Server 2008 і вище та Windows 7.
kwrl

6

IMO, JavaScript поступово стає універсальним стандартом сценаріїв: він, ймовірно, доступний у більшій кількості продуктів, ніж будь-яка інша мова сценаріїв (в Windows він доступний за допомогою Windows Scripting Host). Я маю очистити старі файли у великій кількості папок, тому ось функція JavaScript для цього:

// run from an administrator command prompt (or from task scheduler with full rights):  wscript jscript.js
// debug with:   wscript /d /x jscript.js

var fs = WScript.CreateObject("Scripting.FileSystemObject");

clearFolder('C:\\temp\\cleanup');

function clearFolder(folderPath)
{
    // calculate date 3 days ago
    var dateNow = new Date();
    var dateTest = new Date();
    dateTest.setDate(dateNow.getDate() - 3);

    var folder = fs.GetFolder(folderPath);
    var files = folder.Files;

    for( var it = new Enumerator(files); !it.atEnd(); it.moveNext() )
    {
        var file = it.item();

        if( file.DateLastModified < dateTest)
        {
            var filename = file.name;
            var ext = filename.split('.').pop().toLowerCase();

            if (ext != 'exe' && ext != 'dll')
            {
                file.Delete(true);
            }
        }
    }

    var subfolders = new Enumerator(folder.SubFolders);
    for (; !subfolders.atEnd(); subfolders.moveNext())
    {
        clearFolder(subfolders.item().Path);
    }
}

Щоб очистити кожну папку, просто додайте ще один виклик до функції clearFolder (). Цей конкретний код також зберігає файли exe та dll, а також очищає підпапки.


6

Як щодо цієї модифікації на 7daysclean.cmd врахувати високосний рік?

Це можна зробити менш ніж в 10 рядках кодування!

set /a Leap=0
if (Month GEQ 2 and ((Years%4 EQL 0 and Years%100 NEQ 0) or Years%400 EQL 0)) set /a Leap=day
set /a Months=!_months!+Leap

Редагувати Mofi:

Вищенаведена умова JR оцінюється завжди хибною через неправильний синтаксис.

І Month GEQ 2це також неправильно, оскільки додавання 86400 секунд ще на один день необхідно робити у високосний рік лише за місяці березень-грудень, але не за лютий.

Робочим кодом для врахування високосного дня - лише в поточному році - у пакетному файлі 7daysclean.cmd, опублікованому Джеєм , буде:

set "LeapDaySecs=0"
if %Month% LEQ 2 goto CalcMonths
set /a "LeapRule=Years%%4"
if %LeapRule% NEQ 0 goto CalcMonths
rem The other 2 rules can be ignored up to year 2100.
set /A "LeapDaySecs=day"
:CalcMonths
set /a Months=!_months!+LeapDaySecs

5

Чи можу я додати скромний внесок у цю вже цінну нитку. Я знаходжу, що інші рішення можуть позбутися фактичного тексту помилки, але ігнорують% ERRORLEVEL%, який сигналізує про помилку в моїй програмі. І я законно хочу% ERRORLEVEL% до тих пір, поки це не помилка "Не знайдено файлів".

Деякі приклади:

Налагодження та усунення помилки, зокрема:

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||echo found success

Використовуючи oneliner для повернення ERRORLEVEL успіху чи невдачі:

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT /B 1||EXIT /B 0

Використовуючи oneliner, щоб тримати ERRORLEVEL у нулі для успіху в контексті пакетного файлу посеред іншого коду (ver> nul скидає ERRORLEVEL):

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||ver > nul

Для кроку завдання агента SQL Server CmdExec я зупинився на наступному. Я не знаю, чи це помилка, але CmdExec в рамках кроку розпізнає лише перший рядок коду:

cmd /e:on /c "forfiles /p "C:\SQLADMIN\MAINTREPORTS\SQL2" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT 1||EXIT 0"&exit %errorlevel%

5

Боже, вже багато відповідей. Простий та зручний маршрут, який я знайшов, - виконати ROBOCOPY.EXE двічі в послідовному порядку з однієї інструкції командного рядка Windows, використовуючи параметр & .

ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 & ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 /PURGE

У цьому прикладі він працює, вибираючи всі файли ( . ), Старші 30 днів, і переміщуючи їх до цільової папки. Друга команда знову робить те ж саме, додаючи команду PURGE, що означає видалити файли з цільової папки, які не існують у вихідній папці. Отже, по суті, перша команда MOVES файли, а друга DELETES тому, що вони вже не існують у вихідній папці, коли викликається друга команда.

Зверніться до документації ROBOCOPY та використовуйте перемикач / L під час тестування.


4

Якщо у вас є комплект ресурсів XP, ви можете використовувати робочу копію для переміщення всіх старих каталогів в єдиний каталог, а потім використовувати rmdir для видалення саме цього:

mkdir c:\temp\OldDirectoriesGoHere
robocopy c:\logs\SoManyDirectoriesToDelete\ c:\temp\OldDirectoriesGoHere\ /move /minage:7
rmdir /s /q c:\temp\OldDirectoriesGoHere

4

Я думаю , що відповідь e.James є хорошою, оскільки вона працює з немодифікованими версіями Windows ще в Windows 2000 SP4 (а можливо і раніше), але для цього потрібна запис у зовнішній файл. Ось модифікована версія, яка не створює зовнішній текстовий файл, зберігаючи сумісність:

REM del_old.cmd
REM usage: del_old MM-DD-YYYY
setlocal enabledelayedexpansion
for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;"
for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1)

Щоб відповідати початковому запитанню, тут він знаходиться в скрипті, який робить ВСЕ математику для вас, якщо ви називаєте його числом днів як параметр:

REM del_old_compute.cmd
REM usage: del_old_compute N
setlocal enabledelayedexpansion
set /a days=%1&set cur_y=%DATE:~10,4%&set cur_m=%DATE:~4,2%&set cur_d=%DATE:~7,2%
for /f "tokens=1 delims==" %%a in ('set cur_') do if "!%%a:~0,1!"=="0" set /a %%a=!%%a:~1,1!+0
set mo_2=28&set /a leapyear=cur_y*10/4
if %leapyear:~-1% equ 0 set mo_2=29
set mo_1=31&set mo_3=31&set mo_4=30&set mo_5=31
set mo_6=30&set mo_7=31&set mo_8=31&set mo_9=30
set mo_10=31&set mo_11=30&set mo_12=31
set /a past_y=(days/365)
set /a monthdays=days-((past_y*365)+((past_y/4)*1))&&set /a past_y=cur_y-past_y&set months=0
:setmonth
set /a minusmonth=(cur_m-1)-months
if %minusmonth% leq 0 set /a minusmonth+=12
set /a checkdays=(mo_%minusmonth%)
if %monthdays% geq %checkdays% set /a months+=1&set /a monthdays-=checkdays&goto :setmonth
set /a past_m=cur_m-months
set /a lastmonth=cur_m-1
if %lastmonth% leq 0 set /a lastmonth+=12
set /a lastmonth=mo_%lastmonth%
set /a past_d=cur_d-monthdays&set adddays=::
if %past_d% leq 0 (set /a past_m-=1&set adddays=)
if %past_m% leq 0 (set /a past_m+=12&set /a past_y-=1)
set mo_2=28&set /a leapyear=past_y*10/4
if %leapyear:~-1% equ 0 set mo_2=29
%adddays%set /a past_d+=mo_%past_m%
set d=%past_m%-%past_d%-%past_y%
for /f "tokens=*" %%a IN ('xcopy *.* /d:%d% /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;"
for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1)

ПРИМІТКА. У наведеному вище коді враховуються високосні роки, а також точна кількість днів у кожному місяці. Єдиний максимум - це загальна кількість днів, що пройшли з 0/0/0 (після цього вона повертає негативні роки).

ПРИМІТКА: Математика йде лише одним шляхом; він не може правильно отримати майбутні дати від негативного введення (він спробує, але, швидше за все, минув останній день місяця).


3

Можливо, ви зможете зняти це. Ви можете поглянути на це питання , для більш простого прикладу. Складність настає, коли ви починаєте порівнювати дати. Можливо, легко сказати, чи більша дата чи ні, але є багато ситуацій, які слід врахувати, чи потрібно насправді отримати різницю між двома датами.

Іншими словами - не намагайтеся вигадувати це, якщо ви справді не можете використовувати інструменти сторонніх виробників.


3

це нічого дивовижного, але мені потрібно було зробити щось подібне сьогодні і виконати це як заплановане завдання тощо.

пакетний файл, DelFilesOlderThanNDays.bat нижче із зразком exec w / params:

DelFilesOlderThanNDays.bat 7 C: \ dir1 \ dir2 \ dir3 \ logs * .log

echo off
cls
Echo(
SET keepDD=%1
SET logPath=%2 :: example C:\dir1\dir2\dir3\logs
SET logFileExt=%3
SET check=0
IF [%3] EQU [] SET logFileExt=*.log & echo: file extention not specified (default set to "*.log")
IF [%2] EQU [] echo: file directory no specified (a required parameter), exiting! & EXIT /B 
IF [%1] EQU [] echo: number of days not specified? :)
echo(
echo: in path [ %logPath% ]
echo: finding all files like [ %logFileExt% ]
echo: older than [ %keepDD% ] days
echo(
::
::
:: LOG
echo:  >> c:\trimLogFiles\logBat\log.txt
echo: executed on %DATE% %TIME% >> c:\trimLogFiles\logBat\log.txt
echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt
echo: in path [ %logPath% ] >> c:\trimLogFiles\logBat\log.txt
echo: finding all files like [ %logFileExt% ] >> c:\trimLogFiles\logBat\log.txt
echo: older than [ %keepDD% ] days >> c:\trimLogFiles\logBat\log.txt
echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt
::
FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c echo @path" >> c:\trimLogFiles\logBat\log.txt 2<&1
IF %ERRORLEVEL% EQU 0 (
 FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c echo @path"
)
::
::
:: LOG
IF %ERRORLEVEL% EQU 0 (
 echo:  >> c:\trimLogFiles\logBat\log.txt
 echo: deleting files ... >> c:\trimLogFiles\logBat\log.txt
 echo:  >> c:\trimLogFiles\logBat\log.txt
 SET check=1
)
::
::
IF %check% EQU 1 (
 FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c del @path"
)
::
:: RETURN & LOG
::
IF %ERRORLEVEL% EQU 0 echo: deletion successfull! & echo: deletion successfull! >> c:\trimLogFiles\logBat\log.txt
echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt

3

Розгортаючи відповідь на Аку, я бачу, що багато людей запитують про шляхи до УНК. Просто зіставлення шляху unc до літери диска зробить forfiles щасливим. Зіставлення та розпаковування дисків можна виконати програмно, наприклад, у пакетному файлі.

net use Z: /delete
net use Z: \\unc\path\to\my\folder
forfiles /p Z: /s /m *.gz /D -7 /C "cmd /c del @path"

Це видалить усі файли з розширенням .gz, які старші 7 днів. Якщо ви хочете переконатися, що Z: не відображається ні до чого іншого перед його використанням, ви можете зробити щось просто

net use Z: \\unc\path\to\my\folder
if %errorlevel% equ 0 (
    forfiles /p Z: /s /m *.gz /D -7 /C "cmd /c del @path"
) else (
    echo "Z: is already in use, please use another drive letter!"
)

3

РОБОКОПІЯ прекрасно працює для мене. Спочатку запропонував мій Іман. Але замість переміщення файлів / папок у тимчасовий каталог, а потім видалення вмісту тимчасової папки, перемістіть файли у смітник !!!

Ось декілька рядків мого резервного пакетного файлу, наприклад:

SET FilesToClean1=C:\Users\pauls12\Temp
SET FilesToClean2=C:\Users\pauls12\Desktop\1616 - Champlain\Engineering\CAD\Backups

SET RecycleBin=C:\$Recycle.Bin\S-1-5-21-1480896384-1411656790-2242726676-748474

robocopy "%FilesToClean1%" "%RecycleBin%" /mov /MINLAD:15 /XA:SH /NC /NDL /NJH /NS /NP /NJS
robocopy "%FilesToClean2%" "%RecycleBin%" /mov /MINLAD:30 /XA:SH /NC /NDL /NJH /NS /NP /NJS

Він очищає все, що старше 15 днів, із моєї папки "Темп" і 30 днів - на будь-що в папці резервного копіювання AutoCAD. Я використовую змінні, тому що рядки можуть бути досить довгими, і я можу повторно використовувати їх для інших місць. Вам просто потрібно знайти дос-шлях до вашого кошика, пов'язаний з вашим входом.

Це на робочому комп’ютері для мене і працює. Я розумію, що деякі з вас можуть мати більш обмежувальні права, але все одно спробуйте;) Шукайте пояснення щодо параметрів ROBOCOPY в Google.

Ура!


1
Існуюча друга відповідь, яка найбільше сприймає, також підтримує RoboCopy. Звичайно, ви використовуєте дещо інші варіанти, але це близько до існуючої відповіді.
Джонатан Леффлер

2
У цій публікації є новий вміст - переміщення файлів у кошик. Це ще не запропоновано в Robocopy, і він повністю відповідає оригінальному посту за допомогою вбудованої однорядкової команди. Працює краще, ніж комбінувати команди 'DEL' та 'RMDIR', оскільки файли можна відновити з кошика. Ей, я все ще новий тут - дайте мені перерву;)
Шон Паулішин

2

Мій сценарій для видалення файлів старше певного року:

@REM _______ GENERATE A CMD TO DELETE FILES OLDER THAN A GIVEN YEAR
@REM _______ (given in _olderthanyear variable)
@REM _______ (you must LOCALIZE the script depending on the dir cmd console output)
@REM _______ (we assume here the following line's format "11/06/2017  15:04            58 389 SpeechToText.zip")

@set _targetdir=c:\temp
@set _olderthanyear=2017

@set _outfile1="%temp%\deleteoldfiles.1.tmp.txt"
@set _outfile2="%temp%\deleteoldfiles.2.tmp.txt"

  @if not exist "%_targetdir%" (call :process_error 1 DIR_NOT_FOUND "%_targetdir%") & (goto :end)

:main
  @dir /a-d-h-s /s /b %_targetdir%\*>%_outfile1%
  @for /F "tokens=*" %%F in ('type %_outfile1%') do @call :process_file_path "%%F" %_outfile2%
  @goto :end

:end
  @rem ___ cleanup and exit
  @if exist %_outfile1% del %_outfile1%
  @if exist %_outfile2% del %_outfile2%
  @goto :eof

:process_file_path %1 %2
  @rem ___ get date info of the %1 file path
  @dir %1 | find "/" | find ":" > %2
  @for /F "tokens=*" %%L in ('type %2') do @call :process_line "%%L" %1
  @goto :eof

:process_line %1 %2
  @rem ___ generate a del command for each file older than %_olderthanyear%
  @set _var=%1
  @rem  LOCALIZE HERE (char-offset,string-length)
  @set _fileyear=%_var:~0,4%
  @set _fileyear=%_var:~7,4%
  @set _filepath=%2
  @if %_fileyear% LSS %_olderthanyear% echo @REM %_fileyear%
  @if %_fileyear% LSS %_olderthanyear% echo @del %_filepath%
  @goto :eof

:process_error %1 %2
  @echo RC=%1 MSG=%2 %3
  @goto :eof

1

Цей зробив це для мене. Він працює з датою, і ви можете вилучити потрібну суму за роки, щоб повернутись у часі:

@echo off

set m=%date:~-7,2%
set /A m
set dateYear=%date:~-4,4%
set /A dateYear -= 2
set DATE_DIR=%date:~-10,2%.%m%.%dateYear% 

forfiles /p "C:\your\path\here\" /s /m *.* /d -%DATE_DIR% /c "cmd /c del @path /F"

pause

/Fвcmd /c del @path /F силах файлу конкретного бути видалений в деяких випадках файл може бути тільки для читання.

dateYearце рік Variable і там ви можете змінити для вирахування власних потреб

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.