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

NuclearBox 12-09-2021 00:47 2966445

Скопировать из множества папок по одному самому новому файлу с переименованием.
 
Здравствуйте.

Задача - собрать (скопировать по маске) из множества папок по одному последнему созданному в них файлу в целевую папку. И при копировании присвоить этим файлам имена исходных папок.

Хотелось это сделать через присвоение множества папок одной переменной, поскольку папки могут быть в разных местах и на разную глубину:
Код:

set "F01=D:\FOLDER1"
set "F02=D:\FOLDER2"
set "F03=D:\FOLDER3"
set FSET="%F01%" "%F02%" "%F03%"

, чтобы использовать потом в конструкции
Код:

FOR /D %%d IN (%FSET%) DO
Для копирования последних созданных файлов нашел на форуме код уважаемого megaloman
http://forum.oszone.net/thread-224061.html

Но связать все это вместе не смог.
Прошу помочь. Или подскажите альтернативное решение.

Serguei Kouzmine 12-09-2021 01:53 2966446

@NuclearBox это можно связать вместе костыльным методом показанном ниже
но не рекомендую....займтитесь лучще изучением повершела
может сначала надо определяться задачей, а уже потом выбирать костыли для ее решения

пример

Код:

@echo OFF
setlocal enableextensions enabledelayedexpansion
set LIST=X
set LIST=!LIST! Y
set LIST=!LIST! Z

echo LIST=!LIST!

:LOOP
FOR /F "tokens=1,* delims= " %%a in ('echo !LIST!') do (
SET TOKEN=%%a
set LIST=%%b
call :PROCESS !TOKEN!
if "!LIST!" neq "" GOTO :LOOP
)
goto :EOF
:PROCESS
ECHO processing %1
goto :EOF

получаем
Код:

a.cmd
Код:

LIST=X Y Z
processing X
processing Y
processing Z


alpap 12-09-2021 02:30 2966447

Код:

@echo off
set "d1=C:\Program Files\Internet Explorer"
set "d2=C:\Program Files\7-Zip\Lang"
set "d3=D:\Video\Разное\Животные"
set "out=C:\OUT"

for %%d in ("%d1%" "%d2%" "%d3%") do (
  pushd "%%d"
    for /f "delims=" %%f in ('"dir /a-d/b/o-d/tc|set /p name=^& call echo %%name%%"') do call :#_copy "%%f" "%%d"
  popd
)
pause& exit

:#_copy
  if not exist "%out%" md "%out%"
  copy "%~1" "%out%\%~nx2%~x1"
exit /b

но вот есть такая бяка:
Цитата:

Цитата NuclearBox
при копировании присвоить этим файлам имена исходных папок »

я это выполнил в коде, но предупредить надо. Если будет следующее копирование, файлы затрутся новыми - имена-то одни и те же получаться, может при переименовании делать двойные имена: "Папканоситель_староеимяфайла.ext"?

NuclearBox 12-09-2021 03:11 2966448

Serguei Kouzmine, спасибо за ответ и совет. Код попробую применить, ценно по умолчанию. Советом пока не воспользуюсь, дефицит времени. Ищу именно cmd- или bat-решение.

alpap, спасибо большое, Ваши конструкции больше понимаю и учусь на них.
Останется добавить отбор файлов по маске, думаю с этим справлюсь.
Но по именам Вы правы - файлы затрутся не только при следующем копировании (в моем случае не страшно), но как понимаю и при текущем, если у их папок на диске одинаковое имя. Например,
Код:

set "d1=C:\Program Files\Internet Explorer"
set "d2=C:\Program Files\7-Zip\Lang"
set "d3=D:\Video\Разное\Животные\Lang"

Добавление "староеимяфайла.ext" не спасет, если попадутся файлы и с одинаковыми именами. Есть ли способ добавить не старое имя файла, а имя переменной папки (d1, d2, d3), или порядковый номер, который соответствует их очередности в коде?

Iska 12-09-2021 03:34 2966449

Цитата:

Цитата NuclearBox
…если у их папок на диске одинаковое имя »

Цитата:

Цитата NuclearBox
Добавление "староеимяфайла.ext" не спасет, если попадутся файлы и с одинаковыми именами. »

Именно так.

Если Вы расскажете, что это за файлы, почему они находятся в разных каталогах, с какой именно целью Вы их собираете в одном месте — возможно, Вам подскажут и:
Цитата:

Цитата NuclearBox
альтернативное решение. »

Возможно, даже и не требующее их сбора в одном каталоге :).

alpap 12-09-2021 03:38 2966450

Цитата:

Цитата NuclearBox
или порядковый номер »

Код:

@echo off
set "d1=C:\Program Files\Internet Explorer"
set "d2=C:\Program Files\7-Zip\Lang"
set "d3=D:\Video\Разное\Животные"
set "out=C:\OUT"

for %%d in ("%d1%" "%d2%" "%d3%") do (
  set /a n+=1
  pushd "%%d"
    for /f "delims=" %%f in ('"dir /a-d/b/o-d/tc|set /p name=^& call echo %%name%%"') do call :#_copy "%%~f" "%%~d" "%%n%%"
  popd
)
pause& exit

:#_copy
  if not exist "%out%" md "%out%"
  >nul copy "%~1" "%out%\%~nx2_%~3%~x1"
exit /b

Цитата:

Цитата NuclearBox
добавить отбор файлов по маске »

тогда теряется вся прелесть кода, он берет именно последний созданный и теперь будет писать что не найдет если нет.
маску ставить: ...dir /a-d/b/o-d/tc "сюда" ... и тогда стоит записать так с учетом вышенаписанного: ... 2>nul dir /a-d/b/o-d/tc "сюда" ...

NuclearBox 12-09-2021 04:55 2966451

Iska, это файлы, которые периодически формируют программы и специалисты, и которые долго отслеживать, собирать и обрабатывать вручную. Общий каталог нужен для автоматического формирования итоговых файлов на их основе. Просто автоматизация ежедневной работы.

alpap, Роскошно! Это именно то, что нужно. Супер-Пупер код! Работает идеально. "Сюда" - тоже).
Еще один полигон для изучения. Огромное спасибо!

megaloman 12-09-2021 10:36 2966467

Цитата:

Цитата NuclearBox
Общий каталог нужен для автоматического формирования итоговых файлов на их основе. Просто автоматизация ежедневной работы. »

При такой постановке будете сегодня делать итоговый файл имея в наличии самые разные по времени создания файлы. Прошлогодние файлы тоже годятся?
Цитата:

Цитата NuclearBox
папки могут быть в разных местах и на разную глубину: »

А какое их общее количество? Что, заранее их список неизвестен и они могут появляться/исчезать непредсказуемым для вас образом? Не получится ли так, что одинаковые по смыслу и источнику поступления данные имеются в соседних папках, которые созданы кем-то для сортировки, например, по времени? Хотелось бы проникнуться смыслом задачи.

NuclearBox 12-09-2021 14:50 2966487

megaloman, здравствуйте.

Вероятность получить "древний" документ исключена. Устаревшие на заданную глубину дней документы в этих папках сначала переместятся в подпапки old ( http://forum.oszone.net/thread-349519.html ), следующему процессу они будут не видны.

Общее количество собираемых файлов менее 30. Какие-то формируются строго ежедневно, какие-то без четкой периодичности, по мере готовности.

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

Совпадение файлов по смыслу и источнику исключено, "смыслы" не пересекаются. Это не новостной сборщик, хотя можно, наверное, с доработкой применять батник и для таких задач.

Из собранных файлов постранично формируется несколько профильных файлов + общий документ, автоматизация с помощью конвертеров и Pdftk.

megaloman 12-09-2021 21:33 2966518

Всегда с интересом рассматриваю оригинальное творчество alpap, ИМХО необходимо перед копированием очищать Out.
Немного другой вариант: я не нумерую все файлы, я нумерую файлы только с совпадающими именами, а не сплошняком. Нумерация файлов с одинаковыми именами и разными расширениями из одной папки одинаковая. Учитываю маски.
Код:

@Echo Off
cls
        Set Folders="Z:\Program Files\Internet Explorer" "Z:\Program Files\7-Zip\Lang" "Z:\Video\Разное\Животные" "Z:\Box_In\Program Files\Internet Explorer" "Z:\Box_In\Program Files\7-Zip\Lang" "Z:\Box_In\Video\Разное\Животные"
        Set Mask="*.bat" "2*.xlsx"
        Set "Out=Z:\Out"

        2>nul Pushd "%Out%" &&(2>nul Rd "%Out%" /S /Q &Popd)||(>nul 2>&1 Md "%Out%")

        For %%d In (%Folders%) Do Call :MyCopy "%%~d" "%%~nxd" "%Mask%" "%Out%"
        For /F "usebackq delims=" %%d In (`2^>nul Dir %Folders% /B /S /A:D`) Do Call :MyCopy "%%d" "%%~nxd" "%Mask%" "%Out%"
pause               
Exit /B

:MyCopy
        Pushd %1
        Set "Add="
        If Not Exist "%~4\%~2.*" GoTo :ContMyCopy                                                   
        Set /A i=100
        :Begin
                Set /A i+=1
                Set "Add=_%i:~-2%"
                If Exist "%~4\%~2%Add%.*" GoTo :Begin                                                   
        :ContMyCopy
        Call :MyReCopy %4 %2 "%Add%" %~3
        Popd
Exit /B

:MyReCopy
        If "%~4"=="" Exit /B
        For /F "usebackq delims=" %%f In (`2^>nul Dir %4 /B /A:-D /O:-D /T:W`) Do (>nul Copy "%%f" "%~1\%~2%~3%%~xf" &GoTo :ContMyReCopy)
        :ContMyReCopy
        Shift /4
        GoTo :MyReCopy
Exit /B


NuclearBox 12-09-2021 22:54 2966521

megaloman, большое спасибо. Это как раз то решение, на которое я замахнулся и не осилил.
Не так лаконично, как предложил alpap, но для меня очень ценно, чтобы понимать, как использовать множества папок и масок через общую переменную.
Параметр /s для обхода подпапок исключу, в моем случае он лишний.
По нумерации - вариант, но для визуального контроля удобнее вариант alpap - зная код, можно быстро определить какой файл с повторяющимся именем из какой папки пришел, или не пришел.
С советом предварительно очищать OUT соглашусь и учту.
Очень благодарен.

Еще раз спасибо всем за помощь.

megaloman 12-09-2021 23:04 2966523

Цитата:

Цитата NuclearBox
Параметр /s для обхода подпапок исключу, в моем случае он лишний. »

Уберите красный For и больше ничего не изменяйте.

NuclearBox 12-09-2021 23:52 2966525

megaloman, Точно, спасибо.

megaloman 13-09-2021 00:02 2966528

Цитата:

Цитата NuclearBox
зная код, можно быстро определить какой файл с повторяющимся именем из какой папки пришел, или не пришел »

Не надо знать код, надо задокументировать копирование в .Log-файле.
Код:

@Echo Off
cls
        Set Folders="Z:\Program Files\Internet Explorer" "Z:\Program Files\7-Zip\Lang" "Z:\Video\Разное\Животные" "Z:\Box_In\Program Files\Internet Explorer" "Z:\Box_In\Program Files\7-Zip\Lang" "Z:\Box_In\Video\Разное\Животные"
        Set Mask="*.bat" "2*.xlsx"
        Set "Out=Z:\Out"
        Set "Log=Z:\Out\__%~nx0.log"

        2>nul Pushd "%Out%" &&(2>nul Rd "%Out%" /S /Q &Popd)||(>nul 2>&1 Md "%Out%")

        For %%d In (%Folders%) Do Call :MyCopy "%%~d" "%%~nxd" "%Mask%" "%Out%"
rem        For /F "usebackq delims=" %%d In (`2^>nul Dir %Folders% /B /S /A:D`) Do Call :MyCopy "%%d" "%%~nxd" "%Mask%" "%Out%"
pause               
Exit /B

:MyCopy
        Pushd %1
        Set "Add="
        If Not Exist "%~4\%~2.*" GoTo :ContMyCopy                                                   
        Set /A i=100
        :Begin
                Set /A i+=1
                Set "Add=_%i:~-2%"
                If Exist "%~4\%~2%Add%.*" GoTo :Begin                                                   
        :ContMyCopy
        Call :MyReCopy %1 %4 %2 "%Add%" %~3
        Popd
Exit /B

:MyReCopy
        If "%~5"=="" Exit /B
        For /F "usebackq delims=" %%f In (`2^>nul Dir %5 /B /A:-D /O:-D /T:W`) Do (
                >nul Copy "%%f" "%~2\%~3%~4%%~xf"
                >>"%Log%" Echo "%~2\%~3%~4%%~xf"        ^<---- "%~1\%%f"
                GoTo :ContMyReCopy
        )
        :ContMyReCopy
        Shift /5
        GoTo :MyReCopy
Exit /B


NuclearBox 13-09-2021 00:38 2966530

megaloman, Да, логично, не подумал об этом. Круто и даже избыточно.

Iska 13-09-2021 19:46 2966564

А теперь задача со звёздочкой: если там а) и впрямь копирование, б) в пределах одного раздела, в) в скопированные файлы не вносится изменений — вместо копирования создаём жёсткие ссылки :).


Время: 13:37.

Время: 13:37.
© OSzone.net 2001-