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

592

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

Аналогичные вещи можно сделать в BASH всего за пару строк кода. Кажется, что что-то, по крайней мере, легко можно было сделать для пакетных файлов в Windows. Я ищу решение, которое работает в стандартной командной строке Windows, без каких-либо дополнительных утилит. Пожалуйста, не используйте PowerShell или Cygwin.

  • 7
    Джефф Этвуд ответил на это на Serverfault, который, я думаю, должен быть задокументирован здесь. serverfault.com/questions/49614/delete-files-older-than-x-days
  • 0
    Новый метод, основанный на .BAT-файле, который использует только внутренние команды CMD.EXE, был размещен здесь: stackoverflow.com/questions/9746778/…
Показать ещё 1 комментарий
Теги:
batch-file
date
cmd
file-io

25 ответов

1027
Лучший ответ

Наслаждаться:

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

Смотрите документацию forfile для более подробной информации.

Для получения дополнительной информации см . Индекс 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"
  • 0
    У меня нет файлов на моей машине с XP (sp3) - откуда это взялось?
  • 10
    Должно быть del @FILE, дело обстоит так же. Я предлагаю использовать / c echo @FILE для тестирования
Показать ещё 24 комментария
67

Выполните следующие команды:

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

Переместите все файлы (с помощью /mov, который перемещает файлы, а затем удаляет их в отличие от /move, которые перемещают целые файлы, которые затем удаляются) с помощью robocopy в другое место, а затем выполните команду delete на этом пути, и вы Все хорошо.

Также, если у вас есть каталог с большим количеством данных, вы можете использовать /mir switch

  • 3
    По большей части, это довольно непрактичный ответ. Если у меня есть каталог с большим количеством данных, он не будет работать хорошо. Я бы пошел с одним из ответов, который делает это "на месте"
  • 4
    @ adamb0mb это ни в коем случае нецелесообразно - если «destination» находится в той же файловой системе, что и «source» , операция перемещения довольно легкая. Поскольку robocopy действительно надежен, он фактически работает для любого размера каталога, скрытых имен файлов, в основном произвольной длины пути и включает в себя каталоги, если вам это нужно, - то, чего наверняка нельзя сказать о многих других утилитах Windows. Я бы использовал rd /s /qc:\destination вместо команды del хотя бы использовал другой robocopy /mir c:\emptydir c:\destination чтобы очистить каталог, если вы ожидаете проблем с именами файлов.
Показать ещё 5 комментариев
21

Хорошо было скучно немного и придумал это, в котором содержится моя версия плохой замены 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 строк кода, продолжайте и отправляйте, чтобы добавить его в свой код.

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

ОГРАНИЧЕНИЕ

эпоха принимает как должное, ваш короткий формат даты - ГГГГ-ММ-ДД. Его нужно будет адаптировать для других настроек или оценки времени выполнения (прочитайте sShortTime, пользовательскую конфигурацию, настройте правильный порядок полей в фильтре и используйте фильтр для извлечения правильных данных из аргумента).

Я упоминал, что я ненавижу этот редактор автоформирования? он удаляет пустые строки, а копирование - ад.

Надеюсь, это поможет.

  • 3
    +1 за неразрушающий код, я постараюсь учесть это, когда приведу примеры кода сам.
  • 2
    7daysclean.cmd поздно и совершенно не связано, но 7daysclean.cmd звучит как удивительное название для группы Synth-Punk.
17
forfiles /p "v:" /s /m *.* /d -3 /c "cmd /c del @path"

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

  • 2
    Та же ошибка, что и в других ответах (включая принятый). Откуда появилась эта странная привычка указывать *.* ? Подстановочный знак *.* Не соответствует всем файлам в Windows. Он соответствует только файлам с . в их именах. ОП никогда не говорил ничего о требовании . в имени файла. Правильный параметр - /M * , но в любом случае это значение по умолчанию. Там нет необходимости для /M вообще.
  • 0
    @AnT: ты уверен? Я думаю *.* Ведет себя точно так же, как * в Windows. Фактически, я только что попробовал это на своем компьютере, и dir *.* Действительно перечислил test file , файл без расширения.
Показать ещё 4 комментария
16

Посмотрите на мой ответ на аналогичный вопрос:

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"

Это удаляет файлы старше установленной даты. Я уверен, что его можно изменить, чтобы вернуться через семь дней с текущей даты.

update: Я заметил, что HerbCSO улучшилось на выше script. Я рекомендую использовать его версию.

11

Моя команда

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

@PATH - это просто путь в моем случае, поэтому мне пришлось использовать @PATH\@FILE

также forfiles /? тоже не работает для меня, но forfiles (без "?" ) работал нормально.

И единственный вопрос, который у меня есть: как добавить несколько масок (например,.log |.bak)?

Все это касается forfiles.exe, что я скачал здесь (при победе XP)

Но если вы используете Windows-сервер, то forfiles.exe должен быть уже там, и он отличается от версии ftp. Вот почему я должен изменить команду.

Для Windows Server 2003 я использую эту команду:

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

Для Windows Server 2008 R2:

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

Это приведет к удалению всех файлов .sql старше 90 дней.

6

Использовать файлы.

Существуют разные версии. Ранние используют параметры стиля unix.

Моя версия (для сервера 2000 - отсутствие пробелов после переключателей) -

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

Чтобы добавить forfiles в XP, получите exe из ftp://ftp.microsoft.com/ResKit/y2kfix/x86/

и добавьте его в C:\WINDOWS\system32

  • 11
    @ Kibbee это не тот ответ, синтаксис другой. Это была искренняя попытка помочь. Зная очень мало о командной строке Windows, я потратил часы разочарования, заставляя это работать. Ключевой информацией для меня было то, что есть разные версии (с разным синтаксисом), и мне нужно было убрать пробелы. Ни одна из этих вещей не была включена в первоначальный ответ. (Я бы прокомментировал ответ, но у меня нет привилегий
  • 0
    Та же ошибка, что и в других ответах (включая принятый). Подстановочный forfiles *.* В forfiles не соответствует всем файлам. Он соответствует только файлам с . в их именах (т.е. файлы с расширениями). ОП никогда не говорил ничего о требовании . в имени файла. Правильный параметр - /M * , но в любом случае это значение по умолчанию. Там нет необходимости для /M вообще.
6

Скопируйте этот код и сохраните его как DelOldFiles.vbs.

ИСПОЛЬЗОВАНИЕ ТОЛЬКО В КОМАНДЕ ПРОМПТ: cscript 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
5

Для 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"
  • 0
    Это даже работает в Windows Server 2008 и выше и Windows 7.
5

Часто возникают относительные вопросы, связанные с датой и временем, которые необходимо решить с помощью пакетного файла. Но интерпретатор командной строки cmd.exe не имеет функции для расчета даты/времени. Много хороших рабочих решений, использующих дополнительные консольные приложения или скрипты, уже размещены здесь, на других страницах Qaru и на других веб-сайтах.

Обычно для операций, основанных на дате/времени, требуется преобразовать строку даты/времени в секунды с определенного дня. Очень распространено 1970-01-01 00:00:00 UTC. Но любой последующий день может также использоваться в зависимости от диапазона дат, необходимого для поддержки конкретной задачи.

Jay опубликовано 7daysclean.cmd, содержащее быстрое решение "date to seconds" для командной строки интерпретатор cmd.exe. Но это не требует правильного учета високосных лет. JR разместил надстройку для учета високосного дня в текущем году, но игнорируя другие високосные годы начиная с базового года, т.е. с 1970 года.

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

Этот очень быстрый метод таблицы может использоваться также в пакетном коде с помощью команды FOR. Поэтому я решил закодировать пакетную подпрограмму GetSeconds, которая вычисляет количество секунд с 1970-01-01 00:00:00 UTC для строки даты/времени, переданной этой подпрограмме.

Примечание. Секундомер не учитывается, так как файловые системы Windows также не поддерживают секунд прыжка.

Во-первых, таблицы:

  • Дни с 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-битной переменной без знака, то есть без знака long (или unsigned int) в C/С++.

    Но cmd.exe использует для математических выражений подписанную 32-битную переменную. Поэтому максимальное значение равно 2147483647 (0x7FFFFFFF), которое составляет 2038-01-19 03:14:07.

  • Информация о летальном году (нет/да) за 1970-1970 годы.

    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
    
  • Число дней до первого дня каждого месяца в текущем году.

                       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 в первом цикле FOR GetSeconds, должны быть адаптированы к местному формату даты/времени, если это необходимо.

Необходимо изменить строку даты переменной среды, если формат даты в переменной среды DATE отличается от формата даты, используемого командой FOR на %%~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

Для оптимальной производительности лучше всего удалить все комментарии, т.е. все строки, начинающиеся с rem после 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 часов в пакетном файле с лотами дополнительной информации о времени файла.

5

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 и также очищает подпапки.

5

Как насчет этой модификации на 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:

В приведенном выше выражении J.R. условие всегда оценивается false из-за недействительного синтаксиса.

И Month GEQ 2 также неверно, потому что добавление 86400 секунд в течение еще одного дня должно быть сделано в високосном году только в течение месяцев с марта по декабрь, но не для февраля.

Рабочий код для учета високосного дня - только в текущем году - в пакетном файле 7daysclean.cmd отправлен Jay будет:

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
4

Могу ли я добавить скромный вклад в этот уже ценный поток. Я обнаружил, что другие решения могут избавиться от фактического текста ошибки, но игнорируют% 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 Agent 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%
3

Я думаю, что e.James answer хорош, так как он работает с немодифицированными версиями 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)

Чтобы быть верным исходному вопросу, здесь он находится в script, который делает ВСЕ математику для вас, если вы вызываете ее с количеством дней в качестве параметра:

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

Если у вас есть набор ресурсов XP, вы можете использовать robocopy для перемещения всех старых каталогов в один каталог, а затем использовать rmdir для удаления только одного:

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

Развернувшись на ответе aku, я вижу, что многие спрашивают о путях UNC. Простое отображение пути 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!"
)
2

Это ничего удивительного, но мне нужно было сделать что-то вроде этого сегодня и запускать его как запланированное задание и т.д.

пакетный файл, 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
2

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

Другими словами - не пытайтесь изобрести это, если вы действительно не можете использовать сторонние инструменты.

1

Гоша, уже много ответов. Простой и удобный маршрут, который я нашел, состоял в том, чтобы выполнить ROBOCOP.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 при тестировании.

1

ROBOCOPY отлично работает для меня. Первоначально предложил мой Иман. Но вместо того, чтобы перемещать файлы/папки во временный каталог, а затем удалять содержимое временной папки, переместить файлы в корзину!!!

Это несколько строк моего файла резервной копии, например:

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 дней из моей папки "Temp" и 30 дней для чего-либо в моей резервной папке AutoCAD. Я использую переменные, потому что линия может быть довольно длинной, и я могу использовать их для других мест. Вам просто нужно найти путь dos к корзине, связанной с вашим логином.

Это для меня рабочий компьютер, и он работает. Я понимаю, что некоторые из вас могут иметь более ограничительные права, но в любом случае попробовать его;) Искать в Google пояснения по параметрам ROBOCOPY.

Ура!

  • 1
    Существующий второй по популярности ответ также поддерживает RoboCopy. Конечно, вы используете несколько другие варианты, но это близко к существующему ответу.
  • 2
    В этом посте появился новый контент - перемещение файлов в корзину. Это еще не было предложено в Robocopy, и оно полностью отвечает первоначальному сообщению с использованием встроенной однострочной команды. Работает лучше, чем объединение команд 'DEL' и 'RMDIR', поскольку файлы можно восстановить из корзины. Эй, я все еще новичок здесь - дай мне перерыв;)
0

Blockquote

ФАЙЛЫ -P D:\Backup\-M./D -7/C "CMD/C DEL @path"

Блок цитата блок цитата

  • FORFILES - команда "летучая мышь"
  • -P это путь
  • -M это шаблон файла
  • /D - срок хранения (в днях)
  • /C - команда для запуска в ""
  • DEL, чтобы удалить файл в пути @path из FORFILES
  • ФАЙЛЫ /?

Blockquote

0

My script для удаления файлов старше определенного года:

@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 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
0

Это сделало это для меня. Он работает с датой, и вы можете вычитать желаемое количество в годах, чтобы вернуться во времени:

@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 - это переменная года, и вы можете изменить субстрат на собственные нужды

0

Вероятно, вы не найдете полностью не установленного решения, кроме сложного файла bat или windows script. Я использую delen, поместите его в системный каталог, затем используйте его как обычную команду del в любой bat файл.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню