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

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

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

24 ответов


наслаждайтесь:

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

посмотреть forfile documentation для получения более подробной информации.

дополнительные вкусности, смотрите индекс A-Z командной строки Windows XP.

если у вас нет forfiles установленный на вашем компьютере, скопируйте его из любого Windows Server 2003 к вашей машине Windows XP на %WinDir%\system32\. Это возможно, так как EXE полностью совместим между Windows Server 2003 и Windows XP.

более поздние версии Windows и Windows Server установлены по умолчанию.

Для Windows 7:

синтаксис немного изменился. Поэтому обновленная команда:

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

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

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

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

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


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

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

ограничение

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

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

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


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

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


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

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


мои команды

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

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

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

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

все это касается forfiles.exe, который я скачать тут (на win XP)

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

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

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

Для Windows Server 2008 R2:

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

это удалит все .в SQL файлы старше 90 дней.


скопируйте этот код и сохраните его как 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

использовать forfiles.

есть разные версии. Ранние используют параметры стиля 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


IMO, JavaScript постепенно становится универсальным стандартом сценариев: он, вероятно, доступен в большем количестве продуктов, чем любой другой язык сценариев (в Windows он доступен с помощью узла сценариев Windows). Я должен очистить старые файлы во многих папках, поэтому для этого есть функция 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 файлы и очищает подпапки.


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

условие выше внесено Ж. Р. оценивает всегда false из-за недопустимый синтаксис.

и 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

для 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"

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

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

Джей опубликовано 7daysclean.cmd содержащий быстрое решение "дата-секунды" для интерпретатора командной строки cmd.exe. Но она не учитывает високосные годы. Ж. Р. опубликовал дополнения для принятия високосного дня в текущем году в учет, но игнорирование других високосных лет с базового года, т. е. с 1970 года.

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

этот очень быстрый метод таблицы можно использовать также в пакетном коде, используя на. Поэтому я решил закодировать пакетную подпрограмму 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-разрядной переменной без знака, т. е. unsigned long (или unsigned 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 в первом на цикл GetSeconds необходимо приспособиться к местному формат даты / времени при необходимости.

необходимо адаптировать строку даты переменной окружения, если формат даты в переменной окружения дата отличается от формата даты используется команда на 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 и поэтому не имеет значения, если строка даты переменной среды дата С или без буднего дня, пока день и месяц всегда с 2 цифрами в ожидаемом порядок, т. е. в формате dd/mm/yyyy или dd.mm.yyyy.

вот пакетный код с объяснением комментариев, который просто выводит, какой файл удалить и какой файл сохранить в C:\Temp дерево папок, см. код first на петли.

@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 часов в пакетном файле С большим количеством дополнительной информации о времени файлов.


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

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

для шага задания CmdExec агента SQL Server я приземлился на следующем. Я не знаю, является ли это ошибкой, но 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%

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

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

Я думаю e.Ответ Джеймса!--4--> хорошо, поскольку он работает с немодифицированными версиями 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 (после этого он возвращает отрицательные годы).

Примечание: математика идет только в одну сторону; она не может правильно получить будущие даты от отрицательного ввода (он попытается, но, скорее всего, пройдет мимо последнего дня месяца).


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

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


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

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

DelFilesOlderThanNDays.летучая мышь!--7-->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

расширяя ответ Аку, я вижу, что многие люди спрашивают о путях 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"

это удалит все файлы с помощью a .расширение 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!"
)

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

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

SET FilesToClean1=C:\Users\pauls12\Temp
SET FilesToClean2=C:\Users\pauls12\Desktop16 - 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.

Ура!


Боже, уже много ответов. Простой и удобный маршрут, который я нашел, - это казнить Робокопа.EXE дважды в последовательном порядке из одной инструкции командной строки Windows, используя &


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


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

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


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

@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