Пакетный файл для удаления файлов старше N дней
Я ищу способ удалить все файлы старше 7 дней в пакетном файле. Я искал в Интернете и нашел несколько примеров с сотнями строк кода, а другие, которые требовали установки дополнительных утилит командной строки для выполнения этой задачи.
Подобные вещи можно сделать в BASH всего за пару строк кода. Кажется, что-то хотя бы удаленно можно сделать для пакетных файлов в Windows. Я ищу решение, которое работает в стандартной командной строке Windows, без каких-либо дополнительных утилит. Пожалуйста, не PowerShell или Cygwin либо.
26 ответов
Наслаждаться:
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"
Запустите следующие команды:
ROBOCOPY C:\source C:\destination /mov /minage:7
del C:\destination /q
Переместите все файлы (используя /mov, который перемещает файлы, а затем удаляет их, в отличие от / move, который перемещает целые деревья файлов, которые затем удаляются) с помощью robocopy, в другое место, а затем выполните команду удаления по этому пути, и вы все хорошо.
Также, если у вас есть каталог с большим количеством данных, вы можете использовать /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 дней. Бессекстильные годы - адское дополнение, действительно. если у кого-то есть идея, которая не добавит 10 строк кода, продолжайте и отправьте сообщение, чтобы я добавил его в свой код.
эпоха: я не принимал во внимание время, поскольку необходимо удалить файлы старше определенной даты, так как часы / минуты удалили бы файлы со дня, который предназначался для хранения.
ОГРАНИЧЕНИЕ
Эпоха считает само собой разумеющимся, ваш короткий формат даты YYYY-MM-DD. Его необходимо адаптировать для других настроек или оценки во время выполнения (прочитайте 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 |.bak")?
Все это относительно forfiles.exe, которое я скачал здесь (на win XP)
Но если вы используете сервер Windows, forfiles.exe уже должен быть, и он отличается от версии ftp. Вот почему я должен изменить команду.
Для Windows Server 2003 я использую эту команду:
forfiles -p "d:\Backup" -s -m *.log -d -15 -c "cmd /c del @PATH"
Для 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"
Удалить все файлы старше 3 дней
forfiles -p "C:\folder" -m *.* -d -3 -c "cmd /c del /q @path"
Удалить каталоги старше 3 дней
forfiles -p "C:\folder" -d -3 -c "cmd /c IF @isdir == TRUE rd /S /Q @path"
Очень часто есть относительные вопросы, связанные с датой и временем, которые нужно решить с помощью командного файла. Но интерпретатор командной строки cmd.exe не имеет функции для вычисления даты / времени. Множество хороших рабочих решений, использующих дополнительные консольные приложения или скрипты, уже размещены здесь, на других страницах Stack Overflow и на других веб-сайтах.
Общим для операций, основанных на дате / времени, является требование преобразования строки даты / времени в секунды с определенного дня. Очень часто встречается 1970-01-01 00:00:00 UTC. Но любой последующий день также может быть использован в зависимости от диапазона дат, необходимого для поддержки конкретной задачи.
Jay опубликовал 7daysclean.cmd, содержащий быстрое решение "дата в секундах" для интерпретатора командной строки cmd.exe. Но это не учитывает правильных високосных лет. J.R. опубликовал дополнение для учета високосного дня в текущем году, но игнорирует другие високосные годы с базового года, то есть с 1970 года.
Уже более 20 лет я использую статические таблицы (массивы), созданные один раз с небольшой функцией C, для быстрого получения количества дней, включая високосные дни, с 1970-01-01 в функциях преобразования даты / времени в моих приложениях, написанных на C/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 (или без знака int) в C/C++.
Но cmd.exe использует для математических выражений 32-битную переменную со знаком. Поэтому максимальное значение равно 2147483647 (0x7FFFFFFF), что равно 2038-01-19 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
Преобразование даты в число секунд с 1970-01-01 довольно легко с помощью этих таблиц.
Внимание, пожалуйста!
Формат строк даты и времени зависит от региона Windows и языковых настроек. Разделители и порядок токенов, назначенных переменным среды Day
, Month
а также Year
в первом за цикл GetSeconds
должен быть адаптирован к местному формату даты / времени, если это необходимо.
Необходимо адаптировать строку даты переменной среды, если формат даты в переменной среды DATE отличается от формата даты, используемого командой FOR on %%~tF
,
Например, когда %DATE%
расширяется до Sun 02/08/2015
в то время как %%~tF
расширяется до 02/08/2015 07:38 PM
приведенный ниже код можно использовать с изменением строки 4 для:
call :GetSeconds "%DATE:~4% %TIME%"
Это приводит к переходу на подпрограмму просто 02/08/2015
- строка даты без 3 букв сокращения дня недели и символа разделяющего пробела.
В качестве альтернативы можно использовать следующую для передачи текущей даты в правильном формате:
call :GetSeconds "%DATE:~-10% %TIME%"
Теперь последние 10 символов из строки даты передаются в функцию GetSeconds
и, следовательно, не имеет значения, является ли строка даты переменной среды DATE с или без дня недели, если день и месяц всегда имеют 2 цифры в ожидаемом порядке, то есть в формате dd/mm/yyyy
или же dd.mm.yyyy
,
Вот код пакета с поясняющими комментариями, который просто выводит, какой файл удалить и какой файл сохранить C:\Temp
дерево папок, см. код первого цикла FOR.
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Get seconds since 1970-01-01 for current date and time.
call :GetSeconds "%DATE% %TIME%"
rem Subtract seconds for 7 days from seconds value.
set /A "LastWeek=Seconds-7*86400"
rem For each file in each subdirectory of C:\Temp get last modification date
rem (without seconds -> append second 0) and determine the number of seconds
rem since 1970-01-01 for this date/time. The file can be deleted if seconds
rem value is lower than the value calculated above.
for /F "delims=" %%F in ('dir /A-D-H-S /B /S "C:\Temp"') do (
call :GetSeconds "%%~tF:0"
rem if !Seconds! LSS %LastWeek% del /F "%%~fF"
if !Seconds! LEQ %LastWeek% (
echo Delete "%%~fF"
) else (
echo Keep "%%~fF"
)
)
endlocal
goto :EOF
rem No validation is made for best performance. So make sure that date
rem and hour in string is in a format supported by the code below like
rem MM/DD/YYYY hh:mm:ss or M/D/YYYY h:m:s for English US date/time.
:GetSeconds
rem If there is " AM" or " PM" in time string because of using 12 hour
rem time format, remove those 2 strings and in case of " PM" remember
rem that 12 hours must be added to the hour depending on hour value.
set "DateTime=%~1"
set "Add12Hours=0"
if "%DateTime: AM=%" NEQ "%DateTime%" (
set "DateTime=%DateTime: AM=%"
) else if "%DateTime: PM=%" NEQ "%DateTime%" (
set "DateTime=%DateTime: PM=%"
set "Add12Hours=1"
)
rem Get year, month, day, hour, minute and second from first parameter.
for /F "tokens=1-6 delims=,-./: " %%A in ("%DateTime%") do (
rem For English US date MM/DD/YYYY or M/D/YYYY
set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
rem For German date DD.MM.YYYY or English UK date DD/MM/YYYY
rem set "Day=%%A" & set "Month=%%B" & set "Year=%%C"
set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
)
rem echo Date/time is: %Year%-%Month%-%Day% %Hour%:%Minute%:%Second%
rem Remove leading zeros from the date/time values or calculation could be wrong.
if "%Month:~0,1%" EQU "0" ( if "%Month:~1%" NEQ "" set "Month=%Month:~1%" )
if "%Day:~0,1%" EQU "0" ( if "%Day:~1%" NEQ "" set "Day=%Day:~1%" )
if "%Hour:~0,1%" EQU "0" ( if "%Hour:~1%" NEQ "" set "Hour=%Hour:~1%" )
if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" )
if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" set "Second=%Second:~1%" )
rem Add 12 hours for time range 01:00:00 PM to 11:59:59 PM,
rem but keep the hour as is for 12:00:00 PM to 12:59:59 PM.
if "%Add12Hours%" == "1" (
if %Hour% LSS 12 set /A Hour+=12
)
set "DateTime="
set "Add12Hours="
rem Must use 2 arrays as more than 31 tokens are not supported
rem by command line interpreter cmd.exe respectively command FOR.
set /A "Index1=Year-1979"
set /A "Index2=Index1-30"
if %Index1% LEQ 30 (
rem Get number of days to year for the years 1980 to 2009.
for /F "tokens=%Index1% delims= " %%Y in ("3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245") do set "Days=%%Y"
for /F "tokens=%Index1% delims= " %%L in ("Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N") do set "LeapYear=%%L"
) else (
rem Get number of days to year for the years 2010 to 2038.
for /F "tokens=%Index2% delims= " %%Y in ("14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 21915 22280 22645 23011 23376 23741 24106 24472 24837") do set "Days=%%Y"
for /F "tokens=%Index2% delims= " %%L in ("N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N") do set "LeapYear=%%L"
)
rem Add the days to month in year.
if "%LeapYear%" == "N" (
for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
) else (
for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
)
rem Add the complete days in month of year.
set /A "Days+=Day-1"
rem Calculate the seconds which is easy now.
set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"
rem Exit this subroutine
goto :EOF
Для оптимальной производительности лучше всего удалить все комментарии, то есть все строки, начинающиеся с 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 часов в пакетном файле, с большим количеством дополнительной информации о времени файла".
Для 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"
Чтобы добавить файлы в XP, получите exe-файл с ftp://ftp.microsoft.com/ResKit/y2kfix/x86/
и добавьте его в C:\WINDOWS\system32
Черт возьми, ответов уже много. Простой и удобный маршрут, который я нашел, состоял в том, чтобы выполнить ROBOCOP.EXE дважды в последовательном порядке из одной инструкции командной строки Windows, используя параметр &.
ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 & ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 /PURGE
В этом примере он работает, выбирая все файлы (.) Старше 30 дней и перемещая их в целевую папку. Вторая команда делает то же самое снова с добавлением команды PURGE, которая означает удаление файлов в целевой папке, которые не существуют в исходной папке. По сути, первая команда перемещает файлы, а вторая удаляет, потому что они больше не существуют в исходной папке при вызове второй команды.
Обратитесь к документации ROBOCOPY и используйте переключатель /L при тестировании.
Могу ли я добавить скромный вклад в эту и без того ценную тему. Я обнаружил, что другие решения могут избавиться от фактического текста ошибки, но игнорируют%ERRORLEVEL%, который сигнализирует об ошибке в моем приложении. И я законно хочу%ERRORLEVEL%, только если это не ошибка "Файлы не найдены".
Некоторые примеры:
Отладка и устранение ошибки, в частности:
forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||echo found success
Использование oneliner для возврата ERRORLEVEL успеха или неудачи:
forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT /B 1||EXIT /B 0
Использование oneliner для удержания ERRORLEVEL в нуле для успеха в контексте пакетного файла посреди другого кода (ver > nul сбрасывает ERRORLEVEL):
forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||ver > nul
Для шага задания агента SQL Server CmdExec я обнаружил следующее. Я не знаю, является ли это ошибкой, но CmdExec на этом шаге распознает только первую строку кода:
cmd /e:on /c "forfiles /p "C:\SQLADMIN\MAINTREPORTS\SQL2" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT 1||EXIT 0"&exit %errorlevel%
Как насчет этой модификации на 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
Отредактировано Мофи:
Условие, указанное выше J.R., всегда оценивается как ложное из-за неверного синтаксиса.
А также 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
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, а также очищает подпапки.
Я думаю, что ответ e.James хорош, так как он работает с неизмененными версиями Windows уже в Windows 2000 SP4 (и, возможно, раньше), но требует записи во внешний файл. Вот модифицированная версия, которая не создает внешний текстовый файл при сохранении совместимости:
REM del_old.cmd
REM usage: del_old MM-DD-YYYY
setlocal enabledelayedexpansion
for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;"
for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1)
Чтобы быть верным исходному вопросу, здесь он находится в сценарии, который выполняет ВСЕ математические расчеты за вас, если вы вызываете его с числом дней в качестве параметра:
REM del_old_compute.cmd
REM usage: del_old_compute N
setlocal enabledelayedexpansion
set /a days=%1&set cur_y=%DATE:~10,4%&set cur_m=%DATE:~4,2%&set cur_d=%DATE:~7,2%
for /f "tokens=1 delims==" %%a in ('set cur_') do if "!%%a:~0,1!"=="0" set /a %%a=!%%a:~1,1!+0
set mo_2=28&set /a leapyear=cur_y*10/4
if %leapyear:~-1% equ 0 set mo_2=29
set mo_1=31&set mo_3=31&set mo_4=30&set mo_5=31
set mo_6=30&set mo_7=31&set mo_8=31&set mo_9=30
set mo_10=31&set mo_11=30&set mo_12=31
set /a past_y=(days/365)
set /a monthdays=days-((past_y*365)+((past_y/4)*1))&&set /a past_y=cur_y-past_y&set months=0
:setmonth
set /a minusmonth=(cur_m-1)-months
if %minusmonth% leq 0 set /a minusmonth+=12
set /a checkdays=(mo_%minusmonth%)
if %monthdays% geq %checkdays% set /a months+=1&set /a monthdays-=checkdays&goto :setmonth
set /a past_m=cur_m-months
set /a lastmonth=cur_m-1
if %lastmonth% leq 0 set /a lastmonth+=12
set /a lastmonth=mo_%lastmonth%
set /a past_d=cur_d-monthdays&set adddays=::
if %past_d% leq 0 (set /a past_m-=1&set adddays=)
if %past_m% leq 0 (set /a past_m+=12&set /a past_y-=1)
set mo_2=28&set /a leapyear=past_y*10/4
if %leapyear:~-1% equ 0 set mo_2=29
%adddays%set /a past_d+=mo_%past_m%
set d=%past_m%-%past_d%-%past_y%
for /f "tokens=*" %%a IN ('xcopy *.* /d:%d% /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;"
for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1)
ПРИМЕЧАНИЕ. Приведенный выше код учитывает високосные годы, а также точное количество дней в каждом месяце. Единственный максимум - это общее количество дней, прошедших с 0/0/0 (после этого он возвращает отрицательные годы).
ПРИМЕЧАНИЕ: математика идет только в одну сторону; он не может правильно получить будущие даты из отрицательных входных данных (он попытается, но, скорее всего, пройдет после последнего дня месяца).
Если у вас есть набор ресурсов XP, вы можете использовать robocopy для перемещения всех старых каталогов в один каталог, а затем использовать rmdir, чтобы удалить только этот:
mkdir c:\temp\OldDirectoriesGoHere
robocopy c:\logs\SoManyDirectoriesToDelete\ c:\temp\OldDirectoriesGoHere\ /move /minage:7
rmdir /s /q c:\temp\OldDirectoriesGoHere
РОБОКОПИЯ прекрасно работает для меня. Первоначально предложил мой Иман. Но вместо того, чтобы переместить файлы / папки во временный каталог, а затем удалить содержимое временной папки, переместите файлы в корзину!!!
Это несколько строк моего резервного файла, например:
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.
Ура!
Разбираясь в ответе аку, я вижу много людей, спрашивающих о путях UNC. Простое сопоставление пути unc с буквой диска порадует файлы. Сопоставление и снятие сопоставления дисков может быть сделано программно в пакетном файле, например.
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!"
)
Вы можете быть в состоянии осуществить это. Вы можете взглянуть на этот вопрос, для более простого примера. Сложность наступает, когда вы начинаете сравнивать даты. Может быть легко определить, является ли дата большей или нет, но есть много ситуаций, которые необходимо учитывать, если вам нужно получить разницу между двумя датами.
Другими словами - не пытайтесь изобрести это, если вы действительно не можете использовать сторонние инструменты.
В этом нет ничего удивительного, но мне нужно было сделать что-то подобное сегодня и запустить как запланированное задание и т. д.
командный файл, 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
Мой скрипт для удаления файлов старше определенного года:
@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
Этот сделал это для меня. Он работает с датой, и вы можете вычесть нужную сумму в годах, чтобы вернуться во времени:
@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
Переменная года, и вы можете изменить субстрату в соответствии с вашими потребностями
Более гибкий способ - использовать FileTimeFilterJS.bat
:
@echo off
::::::::::::::::::::::
set "_DIR=C:\Users\npocmaka\Downloads"
set "_DAYS=-5"
::::::::::::::::::::::
for /f "tokens=* delims=" %%# in ('FileTimeFilterJS.bat "%_DIR%" -dd %_DAYS%') do (
echo deleting "%%~f#"
echo del /q /f "%%~f#"
)
Скрипт позволит вам использовать такие измерения, как дни, минуты, секунды или часы. Выбрать погоду для фильтрации файлов по времени создания, доступа или модификации Список файлов до или после определенной даты (или между двумя датами) Выбрать, отображать ли файлы или каталоги (или оба) Быть рекурсивным или нет