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

POSTREALITY 12-02-2019 10:32 2857458

Распределение файлов о папкам, от числового значения в имени файла.
 
Друзья, здравствуйте.
Помогите пожалуйста с решением задачки.

а) Есть куча конечных папок (Обзовём их "B", "C", "D", "E", "F", "G" и "H"), обозначеных как переменные, имя которых является неким бессмысленным числовым значением.
б) Есть изначальная папка, в которой складывается куча файлов, в ЧАСТИ имени каждого из файлов обязательно есть число, которое ТОЧНО совпадает с именем одной из конечных папок.

Задача - распределить все файлы из изначальной папки, в соответствии с пунктами "a" и "b", то-есть:
чтобы файл с именем "файл_01010101.txt" переместился в папку "01010101"
чтобы файл с именем "файл_02020202.txt" переместился в папку "02020202"
чтобы файл с именем "файл_03030303.txt" переместился в папку "03030303"
и так далее.

Туго у меня с FOR и регулярками, по этому прошу помощи.
Всем огромное спасибо!

megaloman 12-02-2019 10:39 2857460

POSTREALITY, количество знаков в числе постоянное? Перед числом обязательно "_"? Число в конце имени? А если папки с подходящим именем нет?

POSTREALITY 12-02-2019 11:10 2857468

megaloman,
"Количество знаков в числе постоянное?" - ДА (во всех случаях - ровно 20 цифр)
Перед числом обязательно "_"? - к сожалению, ДА.
"Число в конце имени?" - ДА
"А если папки с подходящим именем нет?" - в конце скрипта добавлю пересчёт файлов в папке и выведу сообщение в консоль типа "в папке осталось n файлов".
Большое спасибо!

megaloman 12-02-2019 12:02 2857476

Код:

@Echo Off
Cls
        Set "FileIn=Z:\Box_In\*_*.txt"
        Set "Delim=_"
        Set "BoxOut=Z:\Box_Out"

        For %%i In ("%FileIn%") Do Call :Name "%BoxOut%" "%Delim%" "%%i"

        Set /A N=0
        For %%i In ("%FileIn%") Do Set /A N+=1
        Echo !!! Осталось неперемещенными %N% файлов "%FileIn%"
pause
GoTo :Eof

:Name
        Set "S=%~n3"
        :Begin
                Set "SS=%S%
                Call Set "S=%%SS:*%~2=%%"
        If Not "%SS%"=="%S%" GoTo :Begin

rem        If Not Exist "%~1\%S%" Md "%~1\%S%"
        If Not Exist "%~1\%S%" Exit /B 1
        >nul Move /Y %3 "%~1\%S%\"
Exit /B 0


POSTREALITY 12-02-2019 12:31 2857480

megaloman,

Большое спасибо!

Что до :Name примерно понял, что после вообще не понимаю :)

Подскажите пожалуйста, тут есть одно НО:
У меня "%BoxOut%" является не единой директорией. Их под 50 разных. Я их обозначил переменными типа:
SET "00000000000000000000=X:\папка\конечная папка"
SET "11111111111111111111=X:\папка2\подпапка\конечная папка"
SET "22222222222222222222=X:\папка\подпапка2\конечная папка"
SET "33333333333333333333=X:\ещё какой нибудь путь к конечной папке"
Единственное что объединяет конечные папки - они все лежат на одном диске.
Как быть в таком случае?

alpap 12-02-2019 12:40 2857481

Цитата:

Цитата POSTREALITY
У меня "%BoxOut%" является не единой директорией »

а очень желательно сделать именно так потому как
Цитата:

Цитата POSTREALITY
Единственное что объединяет конечные папки - они все лежат на одном диске »

очень затруднит поиск, не сам поиск конкретно, а время, ушедшее на поиск папки по всему диску и еще надо предполагать совпадение имен с возможной другой такой папкой.
И да, лепить в код 50 переменных для путей поддиректорий неблагодарная и неправильная затея.

POSTREALITY 12-02-2019 12:44 2857482

alpap,
Цитата:

Цитата alpap
а очень желательно сделать именно так потому как »

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

Цитата alpap
а время, ушедшее на поиск папки по всему диску »

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

megaloman 12-02-2019 13:17 2857486

Код:

@Echo Off
Cls
        Set "FileIn=Z:\Box_In\*_*.txt"
        Set "Delim=_"

        Set "@@Out1=Z:\Box_Out\01010101"
        Set "@@Out2=Z:\Box_Out\02020202"
        Set "@@Out3=Z:\Box_Out\03030303"

        For %%i In ("%FileIn%") Do Call :Name "@@Out" "%Delim%" "%%i"

        Set /A N=0
        For %%i In ("%FileIn%") Do Set /A N+=1
        Echo !!! Осталось неперемещенными %N% файлов "%FileIn%"
pause
GoTo :Eof

:Name
        Set "S=%~n3"
        :Begin
                Set "SS=%S%
                Call Set "S=%%SS:*%~2=%%"
        If Not "%SS%"=="%S%" GoTo :Begin
        FOR /F "usebackq tokens=1* delims==" %%i IN (`2^>nul Set "%~1"`) DO (
                If "%%~nj"=="%S%" >nul Move /Y %3 "%%j\" &&Exit /B 0
        )
Exit /B 1

Пути для Out-папок могут быть произвольными без "\" на конце

POSTREALITY 12-02-2019 16:27 2857517

megaloman,
Огромное спасибо!

Слегка доработал скрипт под свои нужды, работает все идеально.

P.S.: Не могли бы Вы посоветовать толковую литературу про...

Код:

FOR /F "usebackq tokens=1* delims==" %%i IN (`2^>nul Set "%~1"`) DO (
                If "%%~nj"=="%S%" >nul Move /Y %3 "%%j\" &&Exit /B 0
        )

подобную магию?

megaloman 12-02-2019 16:54 2857520

Цитата:

Цитата POSTREALITY
Не могли бы Вы посоветовать толковую литературу про... »

Как-то напряжно. Чаще всего смотрю Help по командам, например For /?
Здесь на портале есть в начале темы пункт с ссылками.
Но, прежде всего, наибольшую пользу я получаю от разбора решений задач и своих попыток что-то решать своими силами.
Что непонятно - спрашиайте.

Iska 12-02-2019 19:09 2857541

CMD/BAT: Коллекция ссылок.

POSTREALITY 14-02-2019 10:47 2857884

megaloman,
Простите за назойливость, а не могли бы Вы ещё подсказать по данной теме.
Есть у меня вначале скрипта функция
Код:

SET /p prefix="Укажите добавляемый префикс: "
Куда мне надо добавить "%prefix%_", чтобы команда MOVE при переносе, к каждому из файлов добавляла в начало имени указанный пользователем префикс с нижним подчёркиванием (один указанный префикс сразу ко всей текущей порции перемещаемых файлов).
Большое спасибо!

P.S.: Два дня уже пытаюсь найти нормальную статью в интернете, чтобы разобраться с конструкциями типа
Код:

%~n3
и
Код:

"S=%%SS:*%~2=%%"
(совсем не пойму что это значит), к сожалению, поиск толковой статьи пока что не приносит результатов :(

POSTREALITY 14-02-2019 12:08 2857899

megaloman,
Большое спасибо!
Сделал вот так:
Код:

IF "%%~nj"=="%S%" >nul MOVE /Y %3 "%%j\" & REN "%%j\"*.* "%PREFIX%_ИМЯ ФАЙЛА %S%".* &&Exit /B 0
Работает :)

POSTREALITY 14-02-2019 13:07 2857913

megaloman,
Надо в начало имени каждого файла, при перемещении добавить значение из переменной %PREFIX%, которое пользователь изначально вводит при запуске скрипта, функция
Код:

SET /p prefix="Укажите добавляемый префикс: "
Цитата:

Цитата POSTREALITY
Почему сразу в move это не сделать? »

К сожалению, я не могу понять вот эту конструкцию:
Код:

MOVE /Y %3 "%%j\"

POSTREALITY 14-02-2019 13:54 2857927

megaloman,
Обнаружил МОЮ ошибку - названия конечных папок не могут быть произвольными, то есть скрипт считает что имя конечных папок должно полностью совпадать с %S%.
Подскажите пожалуйста, а есть возможность чтобы скрипт не читал имя конечной папки, а просто перемещал файлы по путям, которые указаны в переменных @@Out1, @@Out2, @@Out3 и т.д.?
То есть, необходимо, чтобы скрипт сравнивал только последние 20 цифр имени файла с именем переменной, а имя конечной папки в пути не имело значения.
Огромное спасибо!

megaloman 14-02-2019 15:03 2857949

POSTREALITY, Виноват, не увидел Ваш пост.
при перемещении добавить значение из переменной %PREFIX%, которое пользователь изначально вводит при запуске скрипта
Я ориентировался на постановку задачи, когда имеется полное соответствие цифрового кода файла и имени папки
Код:

@Echo Off
Cls
        Set "FileIn=Z:\Box_In\*_*.txt"
        Set "Delim=_"

        Set "@@Out1=Z:\Box_Out\01010101"
        Set "@@Out2=Z:\Box_Out\02020202"
        Set "@@Out3=Z:\Box_Out\03030303"

        Set /P Prefix="Укажите добавляемый префикс: "

        For %%i In ("%FileIn%") Do Call :Name "@@Out" "%Delim%" "%%i" "%Prefix%"

        Set /A N=0
        For %%i In ("%FileIn%") Do Set /A N+=1
        Echo !!! Осталось неперемещенными %N% файлов "%FileIn%"
pause
GoTo :Eof

:Name
        Set "S=%~n3"
        :Begin
                Set "SS=%S%
                Call Set "S=%%SS:*%~2=%%"
        If Not "%SS%"=="%S%" GoTo :Begin
        FOR /F "usebackq tokens=1* delims==" %%i IN (`2^>nul Set "%~1"`) DO (
                If "%%~nj"=="%S%" >nul Move /Y %3 "%%j\%~4_%~nx3" &&Exit /B 0
        )
Exit /B 1

Попробую объяснить. Для понимания измените For
Код:

        For %%i In ("%FileIn%") Do Echo Call :Name "@@Out" "%Delim%" "%%i" "%Prefix%"
Естественно, после этого скрипт перемещать ничего не будет :), но рассмотрим, что получилось на консоли:
Для каждого из файлов по маске "%FileIn%" вызывается процедура :Name
1 аргумент - префикс переменных для Out-путей
2 - разделитель перед цифровым кодом в конце имени файла
3 - полное имя файла из For
4 - вводимый префикс
В принципе, 1,2,4 аргументы можно было бы и не делать, а в процедуре их нарисовать явным образом, но я считаю, что такая работа с процедурой более гибкая: не надо менять текст процедуры при изменении данных, нужно только изменить параметры при вызове процедуры. Аргументы при вызове взял в кавычки, чтобы было возможным иметь в них пробелы.
Попробуйте вставить после :Name (естественно, без Echo перед Call
Код:

:Name
Echo %1  %2  %3  %4

Вы увидите значения передаваемых аргументов в процедуру при каждом вызове.

Далее, проделайте For /? - полУчите help по For. Еще лучше, сделайте For /? >C:\_For.txt, и читайте в текстовом редакторе этот help.
В самом его конце пояснения конструкций типа %~nI (аналогично и %~n1)
То есть, Set "S=%~n3" позволяет из полного имени файла, переданного в 3 аргументе, выделить его имя в переменную S.
Почему я стараюсь брать равенство после Set в кавычки: чтобы при присваивании к значению не "прицепились" случайные пробелы при создании в текстовом редакторе кода: я не умею работать безошибочно.

Call Set "S=%%SS:*%~2=%%"
Для понимания проделайте Set /? >C:\_set.txt. Почитайте.
Здесь организован неявный цикл: допустим %SS% изначально соответствует тра_ля_ля_суффикс
При первом вызове %тра_ля_ля_суффикс:_*=% получим ля_ля_суффикс, то есть всё, что встретилось до первого вхождения _ "съелось"
Эту операцию проделали несколько раз, чтобы остался только суффикс в конце имени.
Форма вызова Call Set "S=%%SS:*%~2=%%" использована потому, что среди параметров замены использовали переменную %~2

Что Вам нужно:
- чтобы последние 20 знаков в имени файла ТОЧНО соответствовало имени папки?

POSTREALITY 14-02-2019 16:11 2857962

Цитата:

Цитата megaloman
Что Вам нужно:
- чтобы последние 20 знаков в имени файла ТОЧНО соответствовало имени папки? »

Нет. Простите, что не могу с первого раза толком объяснить.

Есть изначальная папка, в ней лежат файлы:
*_00000000000000000000.pdf
*_11111111111111111111.pdf
*_22222222222222222222.pdf
Последние 20 цифр имени файла мы с Вами обозначаем как переменную "S" (на сколько я понял).

Есть переменные, обозначенные как:
Код:

SET "@@Out00000000000000000000=X:\папка\конечная папка"
SET "@@Out11111111111111111111=X:\папка2\подпапка\конечная папка"
SET "@@Out22222222222222222222=X:\папка\подпапка2\конечная папка"
SET "@@Out33333333333333333333=X:\ещё какой нибудь путь к конечной папке"

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

Ещё раз огромное Вам спасибо за помощь и объяснения!

megaloman 14-02-2019 19:59 2858009

Код:

@Echo Off
Cls
        Set "FileIn=Z:\Box_In\*_*.pdf"
        Set /A Len=20

        Set "@@Out01010101010101010101=Z:\Box_Out\Варкалось!"
        Set "@@Out02020202020202020202=Z:\Box_Out\Варкалось!\Хливкие шорьки"
        Set "@@Out03030303030303030303=Z:\Box_Out\Варкалось!\Хливкие шорьки\Пырялись по наве"

        Set /P Prefix="Укажите добавляемый префикс: "

        FOR /F "usebackq tokens=1* delims==" %%i IN (`2^>nul Set "@@Out"`) DO (
                Set "S=%%i"
                Call :Name "%%j" "%%S:~-%Len%%%" "%FileIn%" "%Prefix%_"
        )

        Set /A N=0
        For %%i In ("%FileIn%") Do Set /A N+=1
        Echo !!! Осталось неперемещенными %N% файлов "%FileIn%"
pause
GoTo :Eof

:Name
        Set "In=%~3"
        Call Set "In=%%In:.=%~2.%%"
        For %%f In ("%In%") Do >nul Move /Y "%%f" "%~1\%~4%%~nxf"
Exit /B 0



Время: 14:14.

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