Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Найти, есть ли в папке (и подпапках) изменённые файлы с указанной даты (http://forum.oszone.net/showthread.php?t=206445)

frid-karatel 08-05-2011 18:41 1672643

Найти, есть ли в папке (и подпапках) изменённые файлы с указанной даты
 
Доброго времени суток!

Возник вопрос...
Как можно средствами BAT-файла найти, есть ли изменённые файлы в указанной папке (включая подкапки)?

Вкратце опишу, для чего мне это необходимо:
1. Указываю папку через SET $DEST_DIR=C:\Documents
2. Затем скрипт проверяет, есть ли в папке изменившиеся файлы (хотя бы один)
3. Если есть хотя бы один изменённый файл, то скрипт запускает WinRAR из консоли и делает т.н. резервную копию всей папки
4. Затем созданный архив перемещает на сетевой диск...

Foreigner 08-05-2011 18:55 1672653

frid-karatel,
Цитата:

Цитата 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 1672658

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

Iska 08-05-2011 19:53 1672674

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

Последующее архивирование должно сбрасывать атрибут архивный на указанном для архивировании подмножестве.

amel27 08-05-2011 19:54 1672677

frid-karatel, по мне так вполне должно хватить возможностей WinRAR - он умеет сам искать файлы, измененные со времени последнего бэкапа (ключи -ac, -ao)

Iska 08-05-2011 20:02 1672685

amel27, дык, автору вопроса надо «всю папку с сайтом», а не только архивные файлы. Глупость, конечно. Подобный подход автора к архивированию выглядит, по меньшей мере, нелепым: 3 Виды резервного копирования.

frid-karatel 08-05-2011 20:17 1672698

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

У нас есть сеть из 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 1672713

Цитата:

Цитата frid-karatel
Вот, написал согласно инструкциям Foreigner'а, BAT-файл, но выдаёт "Ошибка в синтаксисе"... »

Ну вот, на вскидку, сразу вижу метки @next и @continue прямо в теле цикла, да еще и с отступом. Имхо, это не айс

Iska 08-05-2011 21:02 1672726

Цитата:

Цитата Foreigner
Ну вот, на вскидку, сразу вижу метки @next и @continue прямо в теле цикла, да еще и с отступом. Имхо, это не айс »

Не айс — это когда вход снаружи внутрь цикла. Используйте без меток, наподобие:
Код:

                IF NOT DEFINED flag (
                                CALL:@check %%i
                        )

Оффтопик:
читать дальше »
Цитата:

Цитата frid-karatel
Далее...
Ведётся работа над N проектами. Допустим, 30 шт.
За день могут быть изменены только 5 проектов, а то и вообще изменений не будет.
Соответственно, надо проверять, были ли какие-нибудь изменения или нет, а потом уже делать резервную копию. »

Не надо. Это задача самого резервного копирования.
Цитата:

Цитата frid-karatel
Далее...
Необходима полная резервная копия всей папки с проектом целиком, а не только измененных файлов.
Чтобы через месяц-другой-третий можно было откатиться и посмотреть/сравнить с тем, что сейчас есть. »

Зачем постоянно полная? Раз в месяц/неделю… В промежутке — резервная копия только изменённых файлов.
Цитата:

Цитата frid-karatel
Далее...
Проекты могут содержать как большие файлы (1 Гб), так и маленькие (1 Кб).
Маленьких файлов может быть... Ну, скажем, 100 000... Соответственно, тут уместно архивирование типа WinRAR. »

А лучше PAQ и KGB Archiver ;). В термине резервное копирование главным является первое слово. Сжатие тут не главное.
Цитата:

Цитата frid-karatel
Далее...
Необходим доступ к резервной копии в любой момент.
Некоторые программы для бэкапа используют резервирование в свой формат, что требует установки софта на каждом компьютере.
А это не есть гуд... »

Разворачиваете полную копию, накатываете на неё частичные архивы вплоть до нужной даты. Хоть тем же WinRar'ом, хоть NT Backup'ом.

Foreigner 08-05-2011 21:13 1672731

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 1672734

А обязательно использовать %%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 1672737

Цитата:

Цитата frid-karatel
Или вместо i можно использовать f, g и вообще, любую другую букву? »

Можно любую -- 0-9, a-z, а-я и всякие #, $, [, ].... Но обычно начинают с %%a или с %%i ( просто по традиции )

Например:
Код:

for /f "tokens=1-3" %%а in ("1 2 3") do echo %%а %%б %%в

Iska 08-05-2011 21:41 1672741

Foreigner, спасибо, интересное замечание.

Foreigner 08-05-2011 22:00 1672757

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 1672758

Так, ошибку в своём коде исправил - заменил некоторые :: на 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 1672771

Цитата:

Цитата frid-karatel
Как из пути "C:\ParentFolder\ChildFolder\SomeChildFolder\" получить путь "S:\Backup\C\ParentFolder\ChildFolder\SomeChildFolder"? »

Код:

set "dir=C:\ParentFolder\ChildFolder\SomeChildFolder\"
set "backup=S:\Backup\%computername%\%dir::=%"

Цитата:

Цитата frid-karatel
Как получить дату создания самого нового файла в папке? »

Код:

for /f "tokens=*" %%i in (' dir /b /od /a-d /tc ') do set "newest_file=%%i"
Цитата:

Цитата frid-karatel
Как обнулить (удалить) переменную $IS_MODIFIED? »

Код:

...

:@check
set "$IS_MODIFIED="
...


frid-karatel 08-05-2011 23:43 1672830

Не получается... Пытаюсь как-то адаптировать, но не могу :)

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 1672874

Цитата:

Цитата frid-karatel
И... почему-то этот код выдаёт слово "Том" вместо даты... »

Это не тот, 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"

amel27 09-05-2011 10:14 1672953

Цитата:

Цитата Foreigner
По поводу меток. Два варианта для исследований »

то, что это может работать не отменяет исходного утверждения 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 1672982

В бесконечном цикле походу 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


)


frid-karatel 09-05-2011 13:06 1673025

Всех с Днём Победы! Ура!

В-общем, доделал я то, что хотел... :)
Вот результат:
Код:

:: ===================================================================================================================================
:: >> Основные настройки скрипта
@ECHO OFF
SETLOCAL enabledelayedexpansion
:: << << <<
:: ===================================================================================================================================
:: >> Назначаем необходимые переменные
:: Папка, куда необходимо копировать резервные копии
SET $BACKUP_DIR_PARENT=S:\Backup
:: Путь до архиватора
SET $WINRAR=C:\Program Files\WinRAR\WinRAR.exe
:: << << <<
:: ===================================================================================================================================
REM >> Определяем массив папок для копирования
SET $FOLDER:01=C:\Documents
SET $FOLDER:02=C:\Letters
SET $FOLDER:03=C:\ThirdFolder
:: ...и так далее...
:: << << <<
:: ===================================================================================================================================
:: >> Список файлов, которые не учитывать при проверки изменения папки
SET $FILE_EXCLUDE:01=Thumbs.db
SET $FILE_EXCLUDE:02=.access_log
SET $FILE_EXCLUDE:03=.error_log
SET $FILE_EXCLUDE:04=.cookie
:: << << <<
:: ===================================================================================================================================
:: >> Проход по всем папкам и проверка, есть ли изменения
FOR /f "tokens=2 delims==" %%f IN ('SET $FOLDER') DO (
        SET $FOLDER_CURRENT=%%f

        REM >> Определяем папку для резервных копий текущей папки
        SET $BACKUP_DIR=!$BACKUP_DIR_PARENT!\!COMPUTERNAME!\!$FOLDER_CURRENT::=!
        REM << << <<

        REM >> Если папки не существует, то создаём её
        IF NOT EXIST "!$BACKUP_DIR!" (
                MKDIR "!$BACKUP_DIR!"
        )
        REM << << <<

        REM >> Определение даты последней резервной копии
        REM Через команду DIR получаем список файлов с расширением RAR
        REM Затем выполняем поиск самого свежего (последнего изменённого) файла
        REM Дату последнего изменения устанавливаем исходя из даты изменения самого свежего файла
        SET $LAST_MODIFIED=0
        PUSHD "!$BACKUP_DIR!"
        FOR /f "tokens=1,2,4" %%a IN ('DIR /TW /A-D-H *.rar ^| findstr /B "[0-9]"') DO (
                FOR /f "tokens=1-5 delims=.:" %%i IN ("%%a.%%b") DO (
                        IF "%%k%%j%%i%%l%%m" GTR "!$LAST_MODIFIED!" (
                                SET $LAST_MODIFIED=%%k%%j%%i%%l%%m
                        )
                )
        )
        POPD
        REM << << <<

        REM >> Выполняем поиск изменённых файлов
        SET $IS_MODIFIED=
        PUSHD "!$FOLDER_CURRENT!"
        FOR /f "tokens=1,2,4" %%a IN ('DIR /S /TW /A-D-H ^| findstr /B "[0-9]"') DO (
                IF NOT DEFINED $IS_MODIFIED (
                        SET $CURRENT_FILE=%%c

                        REM >> Проверяем, находится ли файл в исключениях
                        SET $EXTRUDED=
                        FOR /f "tokens=2 delims==" %%e IN ('SET $FILE_EXCLUDE') DO (
                                IF NOT DEFINED $EXTRUDED (
                                        IF "%%e"=="!$CURRENT_FILE!" (
                                                SET $EXTRUDED=1
                                        )
                                )
                        )
                        REM << << <<

                        REM >> Если файл не находится в исключениях, то обрабатываем его
                        IF NOT DEFINED $EXTRUDED (
                                FOR /f "tokens=1-5 delims=.:" %%i IN ("%%a.%%b") DO (
                                        IF "%%k%%j%%i%%l%%m" GTR "!$LAST_MODIFIED!" (
                                                SET $IS_MODIFIED=1
                                        )
                                )
                        )
                        REM << << <<
                )
        )
        POPD
        REM << << <<

        REM >> Если в папке имеются изменения, то сделать её резервную копию
        IF DEFINED $IS_MODIFIED (
                PUSHD "!$FOLDER_CURRENT!"

                REM >> Если изменения есть, то упаковываем папку в архив
                REM A                                Добавить в архив
                REM -CFG-                        Игнорировать профиль по умолчанию и переменную окружения
                REM -DH                                Открывать совместно используемые файлы
                REM -EP1                        Исключить базовую папку из пути
                REM -INUL                        Не выводить сообщения об ошибках
                REM -M5                                Метод сжатия: максимальный
                REM -R                                Включая вложенные папки
                REM -S                                Создать непрерывный архив
                REM -TL                                Установить время архива по времени новейшего файла
                REM -Y                                Подразумевать ответ "Да" на все вопросы
                REM -X{NAME}                Не обрабатывать файл/папку NAME. [-x*\temp\] - искл. все папки temp и файлы внутри папок temp
                "!$WINRAR!" A "backup" -CFG- -DH -EP1 -INUL -M5 -R -S -TL -Y "!$FOLDER_CURRENT!\"
                REM << << <<

                REM >> Определяем дату самого последнего изменения в папке исходя из даты созданий архива
                REM Через команду DIR получаем строку, содержащую информацию о файле backup
                REM Затем берём из строки дату изменения ГГГГ.ММ.ДД и время ЧЧ:ММ
                REM Согласно полученой дате устанавливаем имя RAR-архива для резервной копии
                FOR /f "tokens=1,2" %%a IN ('DIR /TW /A-D-H backup.rar ^| findstr /B "[0-9]"') DO (
                        FOR /f "tokens=1-5 delims=.:" %%i IN ("%%a.%%b") DO (
                                SET $BACKUP_FILENAME=%%k-%%j-%%i %%l-%%m
                        )
                )
                REM << << <<

                REM >> Перемещаем созданный архив в папку для резервных копий
                MOVE "backup.rar" "!$BACKUP_DIR!\!$BACKUP_FILENAME!.rar"
                REM << << <<

                POPD
        )
        REM << << <<
)
:: << << <<
:: ===================================================================================================================================

Тут ещё есть пара вариантов, которые хочу доработать.
И по одному из них не знаю, как сделать...

В данном случае у меня есть список файлов, которые не учитывать при проверке на последнее изменение - это $FILE_EXCLUDE.
Хотелось бы иметь возможность исключать не только файлы, но и подпапки.
Дело в том, что в некоторых проектах есть HTML-кэш, который изменяется почти каждый час...
Соответственно, папку \cache\ и все её подфайлы/подпапки НЕ надо учитывать при проверке на изменение.
Как такое дело реализовать?

amel27 09-05-2011 13:25 1673039

Цитата:

Цитата Foreigner
В бесконечном цикле походу goto вообще не работает, даже goto:eof, только exit »

На самом деле он и в конечном цикле не работает. Только после завершения цикла переходит на метку - которая может быть в батнике где угодно (в т.ч. оказаться в каком-нибудь цикле). Это отчетливо видно из второго примера.

Foreigner 09-05-2011 14:28 1673080

Цитата:

Цитата amel27
На самом деле он и в конечном цикле не работает. Только после завершения цикла переходит на метку »

Из второго примера как раз видно что цикл прервался, но сначала отработала метка:
Код:

@echo off
setlocal

for /l %%i in (1,1,10) do (

    echo 1: %%i
    if %%i equ 3 goto:break
    echo 2: %%i
   
    :break
    echo 3: %%i 

)
echo end

Цитата:

1: 1
2: 1
3: 1
1: 2
2: 2
3: 2
1: 3
3: %i -- это уже вне цикла, т.к. не работает встроенная переменная %%i
end
Но все же это из разряда хака, нештатное поведение. Обязательное наличие команды на выполнение ( тот же rem )

amel27 10-05-2011 07:08 1673489

Цитата:

Цитата Foreigner
цикл прервался, но сначала отработала метка»

Во-первых, цикл тут как раз не должен прерываться. То, что он останавливается на команде GoTo: говорит как раз в пользу того, что метка не отрабатывает как положено.
Во-вторых, если включить ECHO ON, то видно, что батник на самом деле отрабатывает ВСЕ значения %%i, хотя после GoTo уже вхолостую. Т.е. штатное прерывание циклов FOR не предусмотрено.
В-третьих, ошибка "обязательного наличия команды" никак не связана с циклом - это особенность блока, ограниченного круглыми скобками, пример:
читать дальше »
Код:

(
:LABEL
)


То, что метку интерпретатор считает незавершенной командой говорит как раз в пользу того, что использование меток в блоке не предусмотрено. Блок считывается интерпретатором целиком и выполняется как одна (кэшированная) команда, в то время как переход по метке является самостоятельной файловой операцией (построчного чтения батника), т.е. может исполняться только между "командами".

Foreigner 10-05-2011 16:56 1673798

amel27,
Действительно @echo on показателен и это объясняет отказ от выхода из бесконечного цикла, но все равно поведение не совсем объяснимо. Например:
Код:

@echo on
setlocal

for /l %%i in (0,1,10) do (

    set "var_%%i=%%i"
    if %%i equ 5 goto:break
   
    :break
    rem

)
set var_

Т.е. получается, что после перехода на метку цикл отрабатывает в холостую. Что в принципе может когда-либо пригодиться, но согласен "if решает".

amel27 10-05-2011 17:34 1673826

Цитата:

Цитата Foreigner
получается, что после перехода на метку цикл отрабатывает в холостую »

он отрабатывает вхолостую ПЕРЕД фактическим переходом на метку


команда, которая "сносит крышу" CMD-интерпретатору: :)
P.S. строка должна быть последней в батнике, БЕЗ завершающего CRLF

Foreigner 10-05-2011 19:26 1673892

Цитата:

Цитата amel27
команда, которая "сносит крышу" CMD-интерпретатору: »

Забавно.

amel27 11-05-2011 03:30 1674053

Ещё один момент - приняв правило "не использовать метки в блоках кода, ограниченных круглыми скобками", мы будем вынуждены принять и его следствие: отказаться от применения в блоках нестандартных комментариев по типу меток "::" - только REM.
читать дальше »
Код:

(
:: Комментарий
)


Foreigner 11-05-2011 06:55 1674069

amel27,
Ну так "::" не комментарий, а метка. С таким же успехом можно:
Код:

@echo off

echo 1
:внимание!!! Это как бы комментарий

echo 2 & :пояснение: выводим цифру 2


amel27 11-05-2011 07:12 1674072

Цитата:

Цитата Foreigner
Ну так "::" не комментарий, а метка. »

по сути да, но часто в руководствах этот факт игнорируется, потом привыкаем и ставим тупо "по привычке"... и еще удивляемся почему не работает... ))


Время: 02:44.

Время: 02:44.
© OSzone.net 2001-