Показать полную графическую версию : [решено] Найти, есть ли в папке (и подпапках) изменённые файлы с указанной даты
frid-karatel
08-05-2011, 18:41
Доброго времени суток!
Возник вопрос...
Как можно средствами BAT-файла найти, есть ли изменённые файлы в указанной папке (включая подкапки)?
Вкратце опишу, для чего мне это необходимо:
1. Указываю папку через SET $DEST_DIR=C:\Documents
2. Затем скрипт проверяет, есть ли в папке изменившиеся файлы (хотя бы один)
3. Если есть хотя бы один изменённый файл, то скрипт запускает WinRAR из консоли и делает т.н. резервную копию всей папки
4. Затем созданный архив перемещает на сетевой диск...
Foreigner
08-05-2011, 18:55
frid-karatel,
2. Затем скрипт проверяет, есть ли в папке изменившиеся файлы (хотя бы один) »
Обычно используют xcopy, forfiles, ntbackup, robocopy. Xcopy.exe есть во всех редакциях винды.
Если надо обязательно найти,
@echo off
setlocal
set "ch_date=20110323"
pushd "C:\Documents"
for /f "tokens=1" %%i in (' dir /s /tw /a-d ') do (
if defined flag goto:next
call:check %%i
)
:next
popd
if not defined flag goto:eof
:: Здесь команда создания архива, у меня 7zip
for /f "tokens=1-3 delims=." %%i in ( "%date%" ) do set "archname=%%k-%%j-%%i"
7z a backup_%archname%.7z "C:\Documents"
pushd \\comp\backup
move backup_%date%.7z
popd
goto:eof
:check
for /f "tokens=1-3 delims=." %%i in ( "%1" ) do if %%k%%j%%i geq %ch_date% set "flag=1"
PS. Я тут несколько раз исправлял. Так что повнимательней
frid-karatel
08-05-2011, 19:04
Мне необходимо не скопировать изменившиеся файлы, а узнать, есть ли изменения в папке, изменился ли хотя бы какой-нибудь жалкий файлик с даты, указанной мной...
Например, SET $CH_DATE=20110501. Если с этой даты есть хотя бы какие-нибудь изменения в папке, то выдать, так сказать, true, иначе false :)
Более подробно...
У меня на сетевом диске в папке Backup есть архивы WinRAR...
У архивов имена: 2011-04-13, 2011-04-27, 2011-04-29, 2011-05-01 и т.д.
Каждый день через планировщик Windows будет запускаться BAT-файл, который будет брать имя (дату создания) самого нового архива WinRAR.
Затем в указанных мной папках будет выполняться поиск на наличие изменённых файлов.
Если изменения есть, то будет создаваться новый архив WinRAR с именем как дата самого нового файла.
После создания, архив будет перемещаться на сетевой диск в папку Backup.
Во-от :)
P.S.: Приведу пример, для чего это необходимо...
Имеется локальный веб-сервер, на котором в сети держатся порядка 10ти сайтов и сервисов.
Например, сегодня я решил улучшить один из сайтов, внёс изменения, поправил картинки/скрипты и т.п.
Ночью, когда все спят и никаких изменений не производится, надо сделать резервную копию всей папки с этим сайтом, а не только изменённых файлов.
Чтобы в случае чего можно было не восстановить какие-то файлы из резервной копии, а откатиться целиком на ту версию сайта, которая была, скажем, месяц назад...
В остальных 9ти никаких изменений не произошло, соответственно резервные копии смысла делать нет.
frid-karatel, для размышления: про атрибут файлов «архивный» и его применение в данном случае Вы в курсе? Можете попробовать что-то наподобие:
@echo off
setlocal enableextensions enabledelayedexpansion
set sFolder=%~1
if defined sFolder (
if exist "%sFolder%" (
(dir /s /b /a:a "%sFolder%"|find.exe /v /c "") 1>nul 2>&1 && echo 1 || echo 2
) else (
echo Folder [%sFolder%] not found
)
) else (
echo Usage "%~0" ^<Folder^>
)
endlocal
exit /b
Последующее архивирование должно сбрасывать атрибут архивный на указанном для архивировании подмножестве.
frid-karatel, по мне так вполне должно хватить возможностей WinRAR - он умеет сам искать файлы, измененные со времени последнего бэкапа (ключи -ac, -ao)
amel27, дык, автору вопроса надо «всю папку с сайтом», а не только архивные файлы. Глупость, конечно. Подобный подход автора к архивированию выглядит, по меньшей мере, нелепым: 3 Виды резервного копирования (http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B7%D0%B5%D1%80%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BA%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0 %B0%D0%BD%D0%B8%D0%B5#.D0.92.D0.B8.D0.B4.D1.8B_.D1.80.D0.B5.D0.B7.D0.B5.D1.80.D0.B2.D0.BD.D0.BE.D0.B 3.D0.BE_.D0.BA.D0.BE.D0.BF.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D1.8F).
frid-karatel
08-05-2011, 20:17
Расскажу более детально ситуацию, чтобы понять, почему я пошёл в этом направлении, а не взял какой-нибудь софт для бэкапа...
У нас есть сеть из 5ти компьютеров + 1 компьютер как-бы "серверный".
На серверном компьютере стоят несколько HDD по 2Тб.
Там же лежат разные резервные копии, дистрибутив и т.п. вещи.
Там же запущен локальный WEB-сервер XAMPP.
На нём хостятся с 5 локальных версий сайтов да всякие сервисы типа менеджера задач, органайзера, почты и т.п.
Далее...
Ведётся работа над N проектами. Допустим, 30 шт.
За день могут быть изменены только 5 проектов, а то и вообще изменений не будет.
Соответственно, надо проверять, были ли какие-нибудь изменения или нет, а потом уже делать резервную копию.
Далее...
Необходима полная резервная копия всей папки с проектом целиком, а не только измененных файлов.
Чтобы через месяц-другой-третий можно было откатиться и посмотреть/сравнить с тем, что сейчас есть.
Далее...
Проекты могут содержать как большие файлы (1 Гб), так и маленькие (1 Кб).
Маленьких файлов может быть... Ну, скажем, 100 000... Соответственно, тут уместно архивирование типа WinRAR.
Далее...
Необходим доступ к резервной копии в любой момент.
Некоторые программы для бэкапа используют резервирование в свой формат, что требует установки софта на каждом компьютере.
А это не есть гуд...
BAT-файл я могу конфигурировать так, как мне надо.
К тому же, к нему имеется быстрый доступ и я могу внести в него изменения за несколько секунд, например добавить новую папку...
Я склонялся даже к написанию своей программы на C++, но ввиду того, что среда у меня не установлена, решил сделать BAT'ом.
Потом думал что-то подобное написать на Adobe AIR и JavaScript, но опять же - установка Adobe AIR на все компьютеры - не есть гуд.
Вот такие дела...
Если будут вопросы - могу детальней расписать какой-нибудь пункт ;)
----------------------
Вот, написал согласно инструкциям Foreigner'а, BAT-файл, но выдаёт "Ошибка в синтаксисе"...
::================================================================================================== ==================================
:: >> Основные настройки скрипта
@ECHO OFF
SETLOCAL
:: << << <<
::================================================================================================== ==================================
:: >>Назначаем необходимые переменные
:: Папка, куда необходимо копировать резервные копии
SET $BACKUP_DIR=S:\Backup
:: Путь до архиватора
SET $WINRAR=C:\Program Files\WinRAR\WinRAR.exe
:: Имя компьютера
:: %COMPUTERNAME%
:: Дата, согласно которой проверять файлы на изменение
SET ch_date=20110323
:: << << <<
::================================================================================================== ==================================
:: >> Определяем массив папок для копирования
SET "$FOLDER:01=C:\Documents"
SET "$FOLDER:02=C:\Letters"
SET "$FOLDER:03=C:\ThirdFolder"
:: ...и так далее...
:: << << <<
::================================================================================================== ==================================
:: >> Проход по всем папкам и проверка, есть ли изменения
FOR /f "tokens=2 delims==" %%f IN ('SET $FOLDER') DO (
::Устанавливаем текущий каталог
PUSHD "%%f"
:: >> Выполняем поиск изменённых файлов
FOR /f "tokens=1" %%i IN ('DIR /s /tw /a-d') DO (
IF DEFINED flag GOTO:@next
CALL:@check %%i
:: >> Проверка результата поиска изменённых файлов. Если изменений нет, то ничего не делаем
:@next
POPD
IF NOT DEFINED flag GOTO:@continue
:: << << <<
:: >> Если изменения есть, то упаковываем папку в архив
::A Добавить в архив
::-AG+[FORMAT] Добавить к имени архива текущие дату и время. Если перед FORMAT стоит +, то дата будет добавлена перед именем
::CH -TL Установить время архива по времени новейшего файла
::-DH Открывать совместно используемые файлы
::-EP1 Исключить базовую папку из пути
::-INUL Не выводить сообщения об ошибках
::-M5 Метод сжатия: максимальный
::-S Создать непрерывный архив
::-Y Подразумевать ответ "Да" на все вопросы
::-X{NAME} Не обрабатывать файл/папку NAME. [-x*\temp\] - искл. все папки temp и файлы внутри папок temp
"%$WINRAR%" A -AG+YYYY-MM-DD CH -TL -DH -EP1 -ISNUL -M5 -S -Y "%%f" ""
:: << << <<
:@continue
)
:: << << <<
)
:: << << <<
::================================================================================================== ==================================
GOTO:@exit
::================================================================================================== ==================================
:: >> Поиск изменённых файлов
:@check
FOR /f "tokens=1-3 delims=." %%i IN ("%1") DO (
IF %%k%%j%%i geq %ch_date% SET "flag=1"
)
:: << << <<
::================================================================================================== ==================================
:@exit
PAUSE
Foreigner
08-05-2011, 20:45
Вот, написал согласно инструкциям Foreigner'а, BAT-файл, но выдаёт "Ошибка в синтаксисе"... »
Ну вот, на вскидку, сразу вижу метки @next и @continue прямо в теле цикла, да еще и с отступом. Имхо, это не айс
Ну вот, на вскидку, сразу вижу метки @next и @continue прямо в теле цикла, да еще и с отступом. Имхо, это не айс »
Не айс — это когда вход снаружи внутрь цикла. Используйте без меток, наподобие:
IF NOT DEFINED flag (
CALL:@check %%i
)
Оффтопик:
Далее...
Ведётся работа над N проектами. Допустим, 30 шт.
За день могут быть изменены только 5 проектов, а то и вообще изменений не будет.
Соответственно, надо проверять, были ли какие-нибудь изменения или нет, а потом уже делать резервную копию. »
Не надо. Это задача самого резервного копирования.
Далее...
Необходима полная резервная копия всей папки с проектом целиком, а не только измененных файлов.
Чтобы через месяц-другой-третий можно было откатиться и посмотреть/сравнить с тем, что сейчас есть. »
Зачем постоянно полная? Раз в месяц/неделю… В промежутке — резервная копия только изменённых файлов.
Далее...
Проекты могут содержать как большие файлы (1 Гб), так и маленькие (1 Кб).
Маленьких файлов может быть... Ну, скажем, 100 000... Соответственно, тут уместно архивирование типа WinRAR. »
А лучше PAQ (http://ru.wikipedia.org/wiki/PAQ) и KGB Archiver (http://ru.wikipedia.org/wiki/KGB_Archiver) ;). В термине резервное копирование (http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B7%D0%B5%D1%80%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BA%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0 %B0%D0%BD%D0%B8%D0%B5) главным является первое слово. Сжатие тут не главное.
Далее...
Необходим доступ к резервной копии в любой момент.
Некоторые программы для бэкапа используют резервирование в свой формат, что требует установки софта на каждом компьютере.
А это не есть гуд... »
Разворачиваете полную копию, накатываете на неё частичные архивы вплоть до нужной даты. Хоть тем же WinRar'ом, хоть NT Backup'ом.
Foreigner
08-05-2011, 21:13
Iska,
По поводу меток. Два варианта для исследований:
@echo off
for /l %%i in (0,1,10) do (
if %%i equ 2 goto:break
echo %%i
:break
)
echo 111
@echo off
for /l %%i in (0,1,10) do (
if %%i equ 2 goto:break
echo %%i
:break
rem fake command
)
echo 111
frid-karatel
08-05-2011, 21:24
А обязательно использовать %%i?
Или вместо i можно использовать f, g и вообще, любую другую букву?
Просто с BAT знаком на уровне новичка-любителя... :)
И попутно вопрос...
В моём случае при использовании проверки IF NOT DEFINED необходимо делать undefine для флага $IS_DEFINED... А как?
Ошибка синтаксиса... :(
::================================================================================================== ==================================
:: >> Основные настройки скрипта
@ECHO OFF
SETLOCAL
:: << << <<
::================================================================================================== ==================================
:: >>Назначаем необходимые переменные
:: Папка, куда необходимо копировать резервные копии
SET $BACKUP_DIR=S:\Backup
:: Путь до архиватора
SET $WINRAR=C:\Program Files\WinRAR\WinRAR.exe
:: Имя компьютера
:: %COMPUTERNAME%
:: Дата, согласно которой проверять файлы на изменение
SET $MODIFIED_SINCE=20110323
:: << << <<
::================================================================================================== ==================================
:: >> Определяем массив папок для копирования
SET "$FOLDER:01=C:\Documents"
SET "$FOLDER:02=C:\Letters"
SET "$FOLDER:03=C:\ThirdFolder"
:: ...и так далее...
:: << << <<
::================================================================================================== ==================================
:: >> Проход по всем папкам и проверка, есть ли изменения
FOR /f "tokens=2 delims==" %%i IN ('SET $FOLDER') DO (
:: >> Устанавливаем текущий каталог
SET $FOLDER_CURRENT=%%i
PUSHD "%$FOLDER_CURRENT%"
:: << << <<
:: >> Выполняем поиск изменённых файлов
FOR /f "tokens=1" %%i IN ('DIR /s /tw /a-d') DO (
IF NOT DEFINED $IS_MODIFIED (
CALL:@check %%i
)
)
:: << << <<
:: >> Проверка результата поиска изменённых файлов. Если изменений нет, то ничего не делаем
:@next
POPD
IF NOT DEFINED $IS_MODIFIED (
GOTO:@continue
)
:: << << <<
:: >> Если изменения есть, то упаковываем папку в архив
::A Добавить в архив
::-AG+[FORMAT] Добавить к имени архива текущие дату и время. Если перед FORMAT стоит +, то дата будет добавлена перед именем
::CH -TL Установить время архива по времени новейшего файла
::-DH Открывать совместно используемые файлы
::-EP1 Исключить базовую папку из пути
::-INUL Не выводить сообщения об ошибках
::-M5 Метод сжатия: максимальный
::-S Создать непрерывный архив
::-Y Подразумевать ответ "Да" на все вопросы
::-X{NAME} Не обрабатывать файл/папку NAME. [-x*\temp\] - искл. все папки temp и файлы внутри папок temp
"%$WINRAR%" A -AG+YYYY-MM-DD CH -TL -DH -EP1 -ISNUL -M5 -S -Y "%$FOLDER_CURRENT%" ""
:: << << <<
:@continue
)
:: << << <<
::================================================================================================== ==================================
GOTO:@exit
::================================================================================================== ==================================
:: >> Поиск изменённых файлов
:@check
FOR /f "tokens=1-3 delims=." %%i IN ("%1") DO (
IF %%k%%j%%i geq %$MODIFIED_SINCE% (
SET $IS_MODIFIED=1
)
)
GOTO:eof
:: << << <<
::================================================================================================== ==================================
:@exit
PAUSE
Foreigner
08-05-2011, 21:31
Или вместо i можно использовать f, g и вообще, любую другую букву? »
Можно любую -- 0-9, a-z, а-я и всякие #, $, [, ].... Но обычно начинают с %%a или с %%i ( просто по традиции )
Например:
for /f "tokens=1-3" %%а in ("1 2 3") do echo %%а %%б %%в
Foreigner, спасибо, интересное замечание (http://forum.oszone.net/post-1672731.html#post1672731).
Foreigner
08-05-2011, 22:00
frid-karatel, если вы определяете переменную внутри блока кода ( цикл for, if и т.д. ), ограниченного скобками, то повторное использование этой переменной требует установки 'setlocal enabledelayedexpansion' и использование переменных, заключенных в '!' а не в '%'. В вашем батнике это должно быть так, не проверял:
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "$BACKUP_DIR=S:\Backup"
SET "$WINRAR=C:\Program Files\WinRAR\WinRAR.exe"
SET "$MODIFIED_SINCE=20110323"
SET "$FOLDER:01=C:\Documents"
SET "$FOLDER:02=C:\Letters"
SET "$FOLDER:03=C:\ThirdFolder"
FOR /f "tokens=2 delims==" %%i IN ('SET $FOLDER') DO (
SET "$FOLDER_CURRENT=%%i"
PUSHD "!$FOLDER_CURRENT!"
FOR /f "tokens=1" %%i IN ('DIR /s /tw /a-d') DO (
IF NOT DEFINED $IS_MODIFIED CALL:@check %%i
)
POPD
IF NOT DEFINED $IS_MODIFIED GOTO:@continue
"%$WINRAR%" A -AG+YYYY-MM-DD CH -TL -DH -EP1 -ISNUL -M5 -S -Y "!$FOLDER_CURRENT!" ""
:@continue
REM
)
GOTO:@exit
:@check
FOR /f "tokens=1-3 delims=." %%i IN ("%1") DO (
IF %%k%%j%%i geq %$MODIFIED_SINCE% SET $IS_MODIFIED=1
)
GOTO:eof
:@exit
PAUSE
frid-karatel
08-05-2011, 22:02
Так, ошибку в своём коде исправил - заменил некоторые :: на REM...
Пока выкладывать код не буду - выложу чуть попозже... ;)
Попутно возникли ещё вопросы...
1. Как из пути "C:\ParentFolder\ChildFolder\SomeChildFolder\" получить путь "S:\Backup\C\ParentFolder\ChildFolder\SomeChildFolder"?
Это необходимо, чтобы соблюсти иерархию... Вообще, требуется в результате иметь "S:\Backup\%COMPUTERNAME%\C\ParentFolder\ChildFolder\SomeChildFolder"...
2. Как получить дату создания самого нового файла в папке? В данном случае, мне надо получить дату самого последнего RAR-файла в папке "S:\Backup".
Тут можно попроще что-нибудь, так как имя файла равно дате в формате YYYY-MM-DD
3. Как обнулить (удалить) переменную $IS_MODIFIED? Или она сама обнулится/удалится? Ведь, тогда если в одной папке есть изменения, то переменную надо обнулить/удалить для других папок...
Или делать перед циклом SET $IS_MODIFIED=0, а потом проверять не IF NO DEFINED, а IF $IS_MODIFIED=1?
:)
Foreigner
08-05-2011, 22:16
Как из пути "C:\ParentFolder\ChildFolder\SomeChildFolder\" получить путь "S:\Backup\C\ParentFolder\ChildFolder\SomeChildFolder"? »
set "dir=C:\ParentFolder\ChildFolder\SomeChildFolder\"
set "backup=S:\Backup\%computername%\%dir::=%"
Как получить дату создания самого нового файла в папке? »
for /f "tokens=*" %%i in (' dir /b /od /a-d /tc ') do set "newest_file=%%i"
Как обнулить (удалить) переменную $IS_MODIFIED? »
...
:@check
set "$IS_MODIFIED="
...
frid-karatel
08-05-2011, 23:43
Не получается... Пытаюсь как-то адаптировать, но не могу :)
Foreigner, алгоритм получения даты самого последнего файла не совсем подходит...
Дело в том, что в папке с резервными копиями может появиться файл Thumbs.db, у которого дата изменения будет позже, чем у последней копии, вследствие чего будет "неправильность" :)
Как узнать дату самую последнюю дату изменения RAR файла в папке?
И... почему-то этот код выдаёт слово "Том" вместо даты...
:: >> Поиск изменённых файлов
:@check
SET $IS_MODIFIED=
FOR /f "tokens=1-3 delims=." %%i IN ("%1") DO (
IF %%k%%j%%i geq !$LAST_MODIFIED! (
SET $IS_MODIFIED=1
ECHO %%k%%j%%i
)
)
GOTO:eof
:: << << <<
Foreigner
09-05-2011, 01:13
И... почему-то этот код выдаёт слово "Том" вместо даты... »
Это не тот, a этот:
FOR /f "tokens=1" %%i IN ('DIR /s /tw /a-d ^| findstr /b "[0-9]"') DO (
Добавь что выделено зеленым
Как узнать дату самую последнюю дату изменения RAR файла в папке?
значит ищи только *.rar
for /f "tokens=*" %%i in (' dir /b /od /a-d /tc *.rar ') do set "newest_rar=%%i"
По поводу меток. Два варианта для исследований »
то, что это может работать не отменяет исходного утверждения Iska ;)
- переход по метке не способен обеспечить прерывание цикла;
- обычный IF успешно её заменит и без всякой "путаницы";
- ну и как водится, пара вариантов:
@echo off
SETLOCAL EnableDelayedExpansion
set $i=100
for /l %%i in (0,0,1) do ( set/a $i-=1
if !$i! lss 0 goto:break
set/p .=.<nul
rem
)
:break
echo ---
@echo off
for /l %%i in (0,1,10) do (
if %%i equ 2 goto:break
:break
echo %%i
)
echo ---
Foreigner
09-05-2011, 11:38
В бесконечном цикле походу goto вообще не работает, даже goto:eof, только exit
@echo off
setlocal enabledelayedexpansion
set "n=10"
for /l %%i in (0,0,1) do (
set /a n-=1
0>nul set /p="!n!,"
if !n! leq 0 echo end && 1>nul pause && exit
)
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.