Компьютерный форум 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=181223)

Banzaika 22-07-2010 21:48 1458746

Как из папки выбрать в переменную уникальные имена файлов
 
День добрый,
подскажите, запутался,

есть каталог, в нем файлы типа:
2010.07.21-xx_ab.zip
2010.06.14-xxx.zip
2010.08.21-xx_ab.zip
2010.09.14-xxx.zip
2010.07.11-xx_ab.zip
2010.06.04-xxx.zip
2010.08.26-xx_ab.zip
2010.02.14-xxx.zip

Мне нужна переменная в которой только уникальные имена, т.е. например x=xx_ab xxx

Затык в том, что у меня получается цикл в цикле:
1. бежать в каталоге по именам файлов
2. если в нашей переменной такое имя не встречалось, то set переменная=%переменная% %имя_текущего_файла%
в этом случае второй цикл не хочет просматривать переменную и тем более "на ходу" ее дополнять
Код:

@echo off
SetLocal EnableExtensions
SetLocal EnableDelayedExpansion
set idfile=
for /f "tokens=1* delims=-" %%i in ('dir *.zip /b') do (
for /f "delims= " %%x in (!idfile!) do (
if not %%x == %%j set idfile=!idfile! %%j
)
)
@echo idfile=%idfile%

хотя если собрать все имена файлов в каталоге в 1 переменную, то работает

Код:

@echo off
SetLocal EnableExtensions
SetLocal EnableDelayedExpansion
set idfile=
for /f "tokens=1* delims=-" %%i in ('dir *.zip /b') do (
set idfile=!idfile! %%j
)
echo idfile=%idfile%

но мне нужны в переменной только уникальные имена! иначе дальнейшую обработку не могу организовать...

NiOl 23-07-2010 19:02 1459369

Уточните проблему более подробными примерами - ничего не понятно.

Banzaika 23-07-2010 21:21 1459432

Уточняю:
каждый день на сервере появляются файлы бэкапа в виде zip-архивов.
Эти файлы ВСЕ в имени сначала имеют дату создания, затем уникальное имя - то с чего сделан бэкап.
Этого "то с чего сделан бэкап" у меня около 12 штук.
Вопрос: в каталоге может быть несколько тысяч файлов, но мне нужно знать именно их уникальные имена, то есть с чего это бэкапы.

Пример:
2010.07.21-xx_ab.zip, где
2010.07.21 - дата
xx_ab - уникальное имя

Более того, я уже даже решил проблему, но по извращенному:
Код:

for /f "tokens=1* delims=-" %%i in ('dir *.zip /b') do (echo. > %%j.id)
Эта строка пробегает по именам всех zip в каталоге и отбрасывая первую часть с датой, создает пустой файлик с расширением *.id.
В конечном итоге по этим файликам я точно знаю какие именно бэкапы в каталоге и могу уже использовать их имена для задания маски для дальнейшей обработки.
(мне нужно каждого типа бэкапов хранить всего 5 последних штук, т.е. с сервера-1 5 последних, сервера-2 5 последних и т.д)

Хочу услышать критику и возможно решение через find.
Может кто-то покажет красивее?

Не 1й раз пишу на этом форуме, и хочу предупредить, я хочу решение ИМЕННО в виде bat, на худой конец vbs.
Не предлагайте варианты стороннего ПО, все должно работать "из коробки".

P.S. Почему не обрабатывается переменная цикла в цикле??
Не помню таких ограничений.
т.е. например for %%i do (for %%x do ...) - как обойти ограничение что %х игнорируется??

Не понимаю я
SetLocal EnableExtensions
SetLocal EnableDelayedExpansion
или вернее для передачи переменной в цикл надо ее брать в !переменная!
а как взять в "!" переменную %%i?

Понимаю вопрос задал криво, но вот как есть

QRS 23-07-2010 21:42 1459447

могу предложить первым циклом забросить имена в файл:

Код:

for /f "tokens=1* delims=-" %%i in ('dir *.zip /b') do (
echo %%J >> 1.tmp
)

далее сортируем и идем перебором:

Код:

for /f "delims= " %%x in ('sort 1.tmp') do (
if '!last1!'  NEQ '%%x' set idfile=!idfile! %%x
set last1=%%x
)
echo !idfile!

у себя проверил - работает.
ps: лучше взять временное имя файла и в конце удалить его.

El Sanchez 24-07-2010 13:59 1459801

Цитата:

Цитата Banzaika
мне нужно каждого типа бэкапов хранить всего 5 последних штук, т.е. с сервера-1 5 последних, сервера-2 5 последних и т.д »

Значит все остальное удаляем:
Код:

@Echo Off
SetLocal EnableDelayedExpansion
Set Source=C:\Source
Set NumSavedFiles=5

Set Count=1
Echo.>_UniqueNames.log
For /F "Tokens=1* Delims=-" %%A In ('Dir /B "%Source%\*.zip"') Do (
        Find "%%B" _UniqueNames.log 1>nul 2>&1||Echo %%B>>_UniqueNames.log&&Call :Func "!Count!"
)
Del /F /Q _UniqueNames.log 1>nul 2>&1
EndLocal
GoTo :EOF

:Func
        For /F "Skip=%~1 Tokens=*" %%C In ('Type _UniqueNames.log') Do (
                For /F "Skip=%NumSavedFiles% Tokens=*" %%D In ('Dir /B /O-D /TC "%Source%\*%%C"') Do Del /F /Q "%Source%\%%D" 1>nul 2>&1
        )
        Set /A Count+=1


Banzaika 24-07-2010 15:44 1459875

QRS
В цикле сортировки, если верить подсказке на команду if то операторы сравнения (neq - не равно) допустимо использывать при "расширенной обработке команд"... Точно ли не нужен ключ "/i"???
И не совсем понял сколько раз нужно делать цикл? Ведь будут исключены лишь явно повторяющиеся значения последовательности, например 1123112 превратится в 12312. Мне то на выхлопе нужно получить просто 123...
Может я что-то не правильно понял про команду sort? (фокус с созданием файлов в том что при выполнении цикла они др др заменяют, но в итоге остаются лишь "уникальные")

El Sanchez
Круто, только можно прокомментировать строки? Если честно не все понимаю... хотя и вижу сценарии не 1й раз...

El Sanchez 24-07-2010 19:45 1459992

Banzaika,

Цитата:

Цитата El Sanchez
Echo.>_UniqueNames.log »

Пишем пустую строку в файл _UniqueNames.log, где будет список уникальных имен.

Цитата:

Цитата El Sanchez
For /F "Tokens=1* Delims=-" %%A In ('Dir /B "%Source%\*.zip"') Do (
Find "%%B" _UniqueNames.log 1>nul 2>&1||Echo %%B>>_UniqueNames.log&&Call :Func "!Count!"
) »

Основной цикл. Из вывода команды Dir берем из каждой строки все, что после дефиса, т.е. уникальное имя (переменная %B). Ищем имя в файле _UniqueNames.log (Find "%%B" _UniqueNames.log 1>nul 2>&1) и, если в файле его еще нет (||), то записываем его (Echo %%B>>_UniqueNames.log). Если запись произведена (&&), то вызываем процедуру Func с передаваемым в нее параметром Count - количество строк для пропуска.

Сама процедура:
Цитата:

Цитата El Sanchez
:Func
For /F "Skip=%~1 Tokens=*" %%C In ('Type _UniqueNames.log') Do (
For /F "Skip=%NumSavedFiles% Tokens=*" %%D In ('Dir /B /O-D /TC "%Source%\*%%C"') Do Del /F /Q "%Source%\%%D" 1>nul 2>&1
)
Set /A Count+=1 »

, где For /F "Skip=%~1 Tokens=*" %%C In ('Type _UniqueNames.log') - печатаем наш лог-файл и пропускаем количество строк, заданное в ключевом слове Skip. %~1 - это
наше количество строк Count, переданное из основного цикла. Skip не может начинаться с нуля, по-этому в самом начале и записана пустая строка в _UniqueNames.log.
В попадет последняя строка, содержащая уникальное имя.

For /F "Skip=%NumSavedFiles% Tokens=*" %%D In ('Dir /B /O-D /TC "%Source%\*%%C"') Do Del /F /Q "%Source%\%%D" 1>nul 2>&1 - сортируем все файлы, содержащие в себе уникальное имя %C,
начиная с самого нового (/O-D /TC), пропускаем нужные 5 файлов (%NumSavedFiles%), а все остальное удаляем.

Set /A Count+=1 - увеличиваем количество строк, т.к. при следующем найденном уникальном имени нужно будет пропускать в _UniqueNames.log на строку больше.

El Sanchez 25-07-2010 11:38 1460235

Banzaika,
Вариант №2, попроще и покороче, но время выполнения дольше:
Код:

@Echo Off
Set Source=C:\Source
Set NumSavedFiles=5

For /F "Tokens=1* Delims=-" %%A In ('Dir /B "%Source%\*.zip"') Do (
        For /F "Skip=%NumSavedFiles% Tokens=*" %%C In ('Dir /B /O-D /TC "%Source%\*%%B"') Do Del /F /Q "%Source%\%%C"
)



Время: 21:33.

Время: 21:33.
© OSzone.net 2001-