Пакетный файл для удаления файлов старше N дней
-
09-06-2019 - |
Вопрос
Я ищу способ удалить все файлы старше 7 дней в пакетном файле.Я поискал в Интернете и нашел несколько примеров с сотнями строк кода, а также другие, требующие установки дополнительных утилит командной строки для выполнения задачи.
Подобные вещи могут быть сделано в BASH всего за пару строк кода.Кажется, что для пакетных файлов в Windows можно сделать что-то хотя бы отдаленно простое.Я ищу решение, которое работает в стандартной командной строке Windows без каких-либо дополнительных утилит.Пожалуйста, не используйте PowerShell или Cygwin.
Решение
Наслаждаться:
forfiles -p "C:\what\ever" -s -m *.* -d <number of days> -c "cmd /c del @path"
Видеть форфайловая документация Больше подробностей.
Еще больше вкусностей см. Индекс A-Z командной строки Windows XP..
Если у вас нет forfiles
установлен на вашем компьютере, скопируйте его из любого Windows Сервер 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"
Другие советы
Запустите следующее команды:
ROBOCOPY C:\source C:\destination /mov /minage:7
del C:\destination /q
Переместите все файлы (используя /mov, который перемещает файлы, а затем удаляет их, в отличие от /move, который перемещает целые деревья файлов, которые затем удаляются) с помощью robocopy в другое место, а затем выполните команду удаления по этому пути, и все готово. хороший.
Также, если у вас есть каталог с большим количеством данных, вы можете использовать /mir
выключатель
Оку было немного скучно, и он придумал это, которое содержит мою версию замены эпохи 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 строк кода, опубликуйте ее, чтобы я добавил ее в свой код.
эпоха:Я не учел время, так как необходимо удалить файлы старше определенной даты, часы/минуты привели бы к удалению файлов за день, который предназначался для хранения.
ОГРАНИЧЕНИЕ
эпоха считает само собой разумеющимся, что ваш краткий формат даты — ГГГГ-ММ-ДД.Его необходимо будет адаптировать для других настроек или оценки во время выполнения (прочитайте sShortTime, пользовательскую конфигурацию, настройте правильный порядок полей в фильтре и используйте фильтр для извлечения правильных данных из аргумента).
Я уже упоминал, что ненавижу автоматическое форматирование в этом редакторе?он удаляет пустые строки, а копипаста - это ад.
Надеюсь, это поможет.
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, файл 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
Используйте форфайлы.
Есть разные версии.Ранние используют параметры стиля 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.
Для 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"
ИМХО, 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, а также очищает подпапки.
Как насчет этой модификации на 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
Редактирование Мофи:
Условие выше, вызванное Дж.Р. всегда оценивается как ЛОЖЬ из-за неверного синтаксиса.
И 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
Очень часто возникают вопросы, связанные с относительной датой и временем, которые необходимо решить с помощью пакетного файла.Но интерпретатор командной строки 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 также не поддерживают дополнительные секунды.
Сначала таблицы:
Дней с 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 год с эпохой, начинающейся с 1 января 1970 года, возможно только с использованием беззнаковой 32-битной переменной, т.е.unsigned long (или unsigned int) в C/C++.
Но cmd.exe используйте для математических выражений 32-битную переменную со знаком.Следовательно, максимальное значение — 2147483647 (0x7FFFFFFF), что соответствует 19.01.2038 03:14:07.
Информация о високосном году (Нет/Да) за период с 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
Количество дней до первого числа каждого месяца в текущем году.
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
Преобразовать дату в количество секунд с 1 января 1970 г. с помощью этих таблиц довольно просто.
Внимание, пожалуйста!
Формат строк даты и времени зависит от региона Windows и языковых настроек.Разделители и порядок токенов, назначенных переменным среды. Day
, Month
и Year
во-первых ДЛЯ петля из GetSeconds
при необходимости необходимо адаптировать к местному формату даты/времени.
Необходимо адаптировать строку даты переменной среды, если формат даты в переменной среды ДАТА отличается от формата даты, используемого командой ДЛЯ на %%~tF
.
Например, когда %DATE%
расширяется до Sun 02/08/2015
пока %%~tF
расширяется до 02/08/2015 07:38 PM
приведенный ниже код можно использовать, изменив строку 4 на:
call :GetSeconds "%DATE:~4% %TIME%"
Это приводит к переходу к подпрограмме просто 02/08/2015
- строка даты без трех букв обозначения дня недели и разделительного пробела.
В качестве альтернативы для передачи текущей даты в правильном формате можно использовать следующее:
call :GetSeconds "%DATE:~-10% %TIME%"
Теперь в функцию передаются последние 10 символов строки даты. GetSeconds
и поэтому не имеет значения, является ли строка даты переменной среды ДАТА с днем недели или без него, если день и месяц всегда состоят из двух цифр в ожидаемом порядке, т.е.в формате dd/mm/yyyy
или dd.mm.yyyy
.
Вот пакетный код с поясняющими комментариями, который просто выводит, какой файл удалить, а какой оставить. C:\Temp
дерево папок, см. код первого ДЛЯ петля.
@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 часов в пакетном файле с большим количеством дополнительной информации о времени файла.
Могу ли я внести скромный вклад в эту и без того ценную тему.Я обнаружил, что другие решения могут избавиться от фактического текста ошибки, но игнорируют %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
Использование однострочника для возврата успеха или неудачи 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
Использование однострочника для сохранения 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
На этапе задания 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.Джеймса хорош, поскольку работает с немодифицированными версиями 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 ниже с примером выполнения с параметрами:
DelFilesOlderThanNDays.bat 7 C:\dir1\dir2\dir3\logs *.бревно
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"
При этом будут удалены все файлы с расширением .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.EXE из одной инструкции командной строки Windows, используя команду & параметр.
ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 & ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 /PURGE
В этом примере это работает путем выбора всех файлов (.), которым больше 30 дней, и переместите их в целевую папку.Вторая команда снова делает то же самое с добавлением УДАЛЯТЬ команда, которая означает удаление файлов в целевой папке, которых нет в исходной папке.По сути, первая команда ПЕРЕМЕЩАЕТ файлы, а вторая УДАЛЯЕТ, потому что они больше не существуют в исходной папке при вызове второй команды.
Обратитесь к документации ROBOCOPY и используйте ключ /L при тестировании.
РОБОКОПИЯ у меня отлично работает.Изначально предложил мой Иман.Но вместо перемещения файлов/папок во временный каталог и последующего удаления содержимого временной папки, переместите файлы в корзину!!!
Например, это несколько строк моего пакетного файла резервной копии:
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.Я использую переменные, потому что строка может оказаться довольно длинной, и я могу повторно использовать их для других мест.Вам просто нужно найти путь к корзине, связанный с вашим логином.
У меня это на рабочем компьютере и все работает.Я понимаю, что у некоторых из вас могут быть более ограничительные права, но все равно попробуйте;) Поищите в Google пояснения по параметрам ROBOCOPY.
Ваше здоровье!
Этот сделал это за меня.Он работает с датой, и вы можете вычесть желаемую сумму в годах, чтобы вернуться во времени:
@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