Пакетное создание нескольких папок на основе нескольких имен файлов и перемещение нескольких связанных файлов в созданные папки - PullRequest
1 голос
/ 01 мая 2020

Каждую неделю одному из моих коллег приходилось go через папку с сотнями демультиплексированных видео- и аудиофайлов, переименовывать каждого из них отдельно для конкретной c городской телевизионной станции и затем рассортируйте их по папкам на основе названия города. Я создал файл .bat, чтобы переименовать их все для него, и теперь я хотел бы создать файл .bat, который создает новые каталоги на основе имен файлов и помещает соответствующие файлы в новые папки. Я скопировал несколько файлов для тестирования.

enter image description here

Таким образом, конечным результатом будет папка «Хьюстон» со всеми соответствующими файлами, Папка "Compton" с ее файлами, папка "Moline" и т. Д. c, и c ... для каждого города, примерно до 200 городов, , и мы только получаем больше.

В настоящее время он ищет «Хьюстон», вырезает все файлы, которые создают, вручную создает новую папку, называет ее «Хьюстон» и вставляет все файлы в свою новую папку. ДЛЯ КАЖДОГО ГОРОДА. 200 РАЗ. И это занимает несколько часов.

Файлы ВСЕГДА именуются с помощью этой системы: X ### Случайный город, ST

С моим маленьким крошечным знанием программирования, я предполагаю, что скрипт может обнаружить все символы после первого пробела, а перед запятой скопировать эти символы (случайный город), создать новую папку, присвоить ей имя скопированных символов (случайный город), а затем переместить любые файлы, содержащие «случайный город» в их имени файла, в вновь созданная папка. Конечный результат будет таким, просто с гораздо большим количеством папок.

enter image description here

Есть ли кто-нибудь более продвинутый, чем я, который мог бы объяснить лучший способ к этому?

Я заранее прошу прощения, если я не в том месте или недостаточно подкован. Ура!

ОБНОВЛЕНИЕ: Я возился, узнал о токенах и разделителях, переменных и т. Д. c. Вот то, что у меня работает, что работает удивительно, за исключением того, что я не уверен, как убрать запятую в конце названия города. Я использую пробел в качестве разделителя, который делает текст разбитым на токены, если я правильно понимаю, включая мою запятую, используя tokens = 2. Еще одна проблема, которая возникает; Скажем, есть город с двумя текстовыми кусками (жетонами), например. Сан-Франциско, Батон-Руж. Как я могу схватить их обоих, используя запятую как точку остановки? Мой код приведен ниже.

@echo off
setlocal enabledelayedexpansion
for %%A in (*.m2v *.mpa) do (
   echo file found  %%A
   for /f "delims=" %%B in ("%%A") do set fname=%%~nB
   for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
   for /f "tokens=2* delims= " %%D in ("!fname!") do set folname=%%D
   echo folder name !folname!
   if not exist "!folname!" (
      echo Folder !folname! doesn't exist, creating
      md "!folname!"
   ) else (
      echo Folder !folname! exists
   )
   echo Moving file %%A to folder !folname!
   move "%%A" "!folname!"
   )
echo Finished

pause

ОБНОВЛЕНИЕ 2: Я нашел обходной путь meh, чтобы избавиться от запятой, добавив его в качестве разделителя, но я все еще пытаюсь обернуть моя голова вокруг 2 городов слова. Мои папки «Батон-Руж» и «Сан-Франциско» называются соответственно «Батон» и «Сан». Вот мой код, я обновлю его, если найду лучший способ.

setlocal enabledelayedexpansion
for %%A in (*.m2v *.mpa) do (
   echo file found  %%A
   for /f "delims=" %%B in ("%%A") do set fname=%%~nB
   for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
   for /f "delims=," %%B in ("%%A") do set fname=%%~nB
   for /f "tokens=2* delims= " %%D in ("!fname!") do set folname=%%D
   echo folder name !folname!
   if not exist "!folname!" (
      echo Folder !folname! doesn't exist, creating
      md "!folname!"
   ) else (
      echo Folder !folname! exists
   )
   echo Moving file %%A to folder !folname!
   move "%%A" "!folname!"
   )
echo Finished

pause

ОБНОВЛЕНИЕ 3

Вот мой код, который работал. Однако, если количество символов в префиксах / суффиксах вашего имени файла изменится, это все испортит, и вам придется редактировать код.

@ECHO OFF
SETLOCAL enabledelayedexpansion
FOR %%A in (*.m2v *.mpa) do (
   ECHO file found  %%A
   FOR /F "delims=" %%B in ("%%A") do set fname=%%~nB
   SET folname=!fname:~5,-4!
   ECHO folder name !folname!
   if not exist "!folname!" (
      ECHO Folder !folname! doesn't exist, creating
      MD "!folname!"
   ) else (
      ECHO Folder !folname! exists
   )
   ECHO Moving file %%A to folder !folname!
   MOVE "%%A" "!folname!"
   )
ECHO Finished

PAUSE

Использование SET folname=!fname:~5,-4! позволяет мне обрезать префикс M373 , 5 символов, и, суффикс TX, 4 символа, удаляя запятую и спасая название города, независимо от его длины или количества слов (например, West Palm Beach, FL). Антарес упомянул об этом решении в своем ответе, который работал как шарм.

Но это также заставило меня задуматься

Если количество символов в префиксе изменится, что вполне вероятно, мне придется каждый раз редактировать пакетный файл каждый раз или создайте указанный c пакетный файл для каждого обстоятельства. Не страшно, но и не здорово. Поэтому я согласился с ответом Майкла Хита, который работает безупречно. Я еще не достаточно умен, чтобы точно знать, почему, но я расскажу об этом и выясню. Я многому учусь. Спасибо всем! Before After

Ответы [ 5 ]

0 голосов
/ 05 мая 2020

Когда мне нужно было разработать скрипт для поставленной задачи, я бы, вероятно, реализовал несколько функций безопасности, чтобы не перемещать неправильные файлы. Ваш пример данных показывает пары файлов .m2v и .mpa, но я, скорее всего, не считаю это само собой разумеющимся. Также я бы не стал полагаться на префикс фиксированной длины. Наконец, я, возможно, также учел бы lit s comment .

Итак, вот моя попытка (см. Все пояснительные rem -марки в коде) :

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=%~dp0."         & rem // (root directory containing the files to be processed)
set "_MASK=M??? *, ??.m2v" & rem // (mask to find the files to be processed)
set _EXTS=".m2v" ".mpa"    & rem /* (list of extensions that must all be present;
                             rem     expensions are not checked if this is empty;
                             rem     `_MASK` should then be changed to end with `.m*`) */
set "_FILT=^M[0-9][0-9][0-9] [^,][^,]*, [A-Z][A-Z]\.[^\.][^\.]*$"
                             rem // (additional filter to find files; deactivate by `.*`)
set "_SEPS=,"              & rem /* (defines (a) separator character(s) to derive the
                             rem     sub-directory; leave it blank to use full name) */

rem // Change into the root directory:
pushd "%_ROOT%" && (
    rem /* Loop through all files matching the mask as well as the additional filter;
    rem    if the post-filtering is not needed, remove `^|` and everything behind: */
    for /F "delims= eol=|" %%F in ('
        dir /B /A:-D-H-S "%_MASK%" ^| findstr /I /R /C:"%_FILT%"
    ') do (
        rem // Get the portion in front of the `,` of the file name:
        for /F "delims=%_SEPS% eol=|" %%G in ("%%~nF") do (
            rem // Split that portion at the first space to get the city name:
            for /F "tokens=1* eol=|" %%H in ("%%G") do (
                rem // initialise flag that indicates whether to move the current file:
                set "FLAG=#"
                rem // Skip the following checks if there are no extensions defined:
                if defined _EXTS (
                    rem // Loop through the extensions in the list:
                    for %%E in (%_EXTS%) do (
                        rem /* Reset flag if file with current name and iterated extension
                        rem    cannot be found; this ensures that files with all listed
                        rem    extensions do exist, otherwise no files are moved: */
                        if not exist "%%~nF%%~E" set "FLAG="
                        rem /* Reset flag if file with current name and iterated extension
                        rem    is actually a directory (though this is very unlikely): */
                        rem if exist "%%~nF%%~E\" set "FLAG="
                        rem /* Reset flag if file with current name and iterated extension
                        rem    is already located in the target sub-directory: */
                        if exist "%%I\%%~nF%%~E" set "FLAG="
                    )
                )
                rem // Do the following steps only if the flag has not been reset:
                if defined FLAG (
                    rem // Create target sub-directory (suppress potential error message):
                    2> nul md "%%I"
                    rem // Check if there are dedicated extensions defined:
                    if defined _EXTS (
                        rem // Loop through the extensions in the list again:
                        for %%E in (%_EXTS%) do (
                            rem /* Move file with current name and iterated extension;
                            rem    nothing is overwritten due to the preceding checks: */
                            > nul move "%%~nF%%~E" "%%I\%%~nF%%~E"
                        )
                    ) else (
                        rem /* Empty list of extensions, hence just move the current file;
                        rem    if you do want to overwrite, remove the `if exist´ part: */
                        if not exist "%%I\%%F" > nul move /Y "%%F" "%%I\%%F"
                    )
                )
            )
        )
    )
    rem // Return from root directory:
    popd
)

endlocal
exit /B

Значения в разделе Define constants here: в верхней части скрипта определены в соответствии с вашими примерами данных, но их можно легко адаптировать для настройки скрипта в одном месте:

  • _ROOT: указывает на каталог, в котором находятся ваши входные файлы; %~dp0. указывает на родительский каталог скрипта, но вы, конечно, можете указать здесь любой другой абсолютный путь к каталогу;
  • _MASK: это шаблон файла, который соответствует одному файлу на пару (только .m2v файлы, остальные покрыты _EXTS); M??? соответствует четырехсимвольному префиксу, но вы можете изменить его, например, на M?*, чтобы также соответствовать префиксам, таким как M1 или M9999; однако, если вы это сделаете, также отредактируйте _FILT соответственно;
  • _EXTS: определяет список расширений, которые должны присутствовать все; это означает, что для определенного базового имени файла (например, M372 Houston, TX, должен существовать файл для каждого данного расширения, следовательно, M372 Houston, TX.m2v и M372 Houston, TX.mpa в нашей ситуации, в противном случае эти файлы не будут перемещены; если вы этого не сделаете, Позаботьтесь, если такая пара завершена или нет, просто укажите set "_EXTS=" (очистите его) и измените расширение _MASK с .m2v на .m*, чтобы все файлы с расширением, начинающимся с .m, были перемещены ;
  • _FILT: создает дополнительный фильтр для имен файлов, чтобы исключить неправильные файлы, в настоящее время это также отражает четырехсимвольный префикс, но если это не всегда так, просто измените M[0-9][0-9][0-9] на M[0-9]*; если вы не хотите фильтровать, установите это значение на .*, чтобы оно соответствовало всем;
  • _SEPS: определяет символ (ы) для разделения имени базового файла для получения соответствующий подкаталог, поэтому все, заканчивающееся перед этим символом и начинающееся после первого SPACE , является результирующим именем подкаталога: если вы не определите здесь символ, весь оставшееся базовое имя файла (то есть все после первого SPACE до, но не включая (последний) .) занято;
0 голосов
/ 01 мая 2020

Вот альтернативный метод, только для разнообразия :

@Echo Off
SetLocal DisableDelayedExpansion

Set "SourceDir=.\Batch Rename\BACKUP"

If Exist "%SourceDir%\" For /F "EOL=|Delims=" %%G In (
    '%__AppDir__%where.exe "%SourceDir%":"*, ??.m??" 2^>NUL'
)Do (Set "FileBaseName=%%~nG"&SetLocal EnableDelayedExpansion
    For /F "EOL=|Delims=," %%H In ("!FileBaseName:* =!")Do (EndLocal
    %__AppDir__%Robocopy.exe "%%~dpG." "%%~dpG%%H" "%%~nxG" /Mov>NUL))

Этот метод фильтрует ваши файлы с помощью команды where. Для перемещения выбираются только имена файлов, которые заканчиваются запятой, за которой следует пробел, за которым следуют две буквы, за которыми следует трехбуквенное расширение, начинающееся с символа m. Он перемещает файлы, автоматически создавая каталоги назначения, если они не существуют, с помощью команды robocopy. Он использует только два цикла for, второй из которых изолирует строку между первым пробелом и следующей запятой.

Я сделал это так, чтобы скрипт мог находиться где угодно, не обязательно в каталоге с файлами. Это местоположение задается в строке 3 сценария. Если вы хотите изменить его sh, убедитесь, что ваше местоположение остается между = и закрывающей двойной кавычкой " и не заканчивается на отставая бэк-шла sh, \. В настоящее время он установлен в относительный каталог (в зависимости от того, что видно на скриншоте) , но вы также можете использовать абсолютный путь, например, Set "SourceDir=C:\Users\UserName\Videos". Если вы хотите sh сохранить скрипт в том же каталоге, что и файлы, которые нужно переместить, измените его на Set "SourceDir=." и просто дважды щелкните по нему для запуска.

0 голосов
/ 01 мая 2020

Я могу дать вам несколько советов. Если у вас более конкретный c проблемный случай, не стесняйтесь обновить ваш вопрос еще раз.

Вы можете вырезать последние X символов строки следующим образом: %variablename:~0,-X%

Если вам известны переменные с городскими частями, например, %% D и %% E или что-то еще, вы можно объединить их снова, как это md "%%D %%E". Однако это работает только для фиксированного числа токенов, как здесь два.
Вы можете сохранить это объединение в собственной переменной, если вам нужен результат за пределами вашего for-l oop. Используйте, например, set myVariable=%%D %%E и покажите его с %myVariable% или !myVariable! (когда требуется отложенное расширение), например, md "%myVariable%".

Отличный обходной путь: если имеется только небольшое число «специальные города», чтобы принять во внимание, тогда вы можете просто добавить некоторые команды переименования в конце вашего скрипта, такие как rename San "San Francisco", rename Baton "Baton Rouge", et c. Не будет хорошо работать, если есть больше городов "Сан" (например, "Сан Бернадино"), потому что это уже невозможно различить. Но в этом случае копирование в отдельные папки также завершится неудачей.

В вашем скрипте вы проверяете существующую папку. Я думаю, что вы можете опустить это. md или mkdir либо создайте этот каталог, либо ничего не делайте, если он существует. Что ж, они выводят на консоль сообщение, которое можно игнорировать. Если вы не хотите их видеть, перенаправьте поток сообщений об ошибках на nul, например md myFolder 2>nul. Это поглотит любые сообщения об ошибках, но маловероятно, что вы получите какое-либо другое сообщение об ошибке, отличное от вашего сценария.

Вы можете упростить свой подход следующим образом: я считаю, что переименование вашего файла работает хорошо. Ваш сценарий «копирования» может быть просто списком команд, которые указаны явно (и также могут быть отредактированы довольно быстро, если будут рассматриваться новые города).
Установите пакетный файл следующим образом с записями для каждого города:

@echo off
mkdir "Moline"
copy "*Moline*.*" "Moline"

mkdir "San Francisco"
copy "*San Francisco*.*" "San Francisco"

...

echo done.

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

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

В командной строке вы можете получить обширную помощь, выполнив используемые команды в вашем пакетном файле и добавив /?. Например, set /? дает вам много полезных вещей, которые вы можете делать с переменными / манипуляциями со строками.
Попробуйте: for /?, if /? (например, errorlevel), возможно call /?, goto /? и др.

Очень хорошим источником для всех команд командной строки является https://www.ss64.com. Этот сайт предоставляет обширную помощь даже для PowerShell и Linux Bash и других. В этом случае для вас будет иметь значение CMD, прямая ссылка: https://ss64.com/nt/

Редактирование / обновление:
Проверьте замену символа на set команда для создания чего-то вроде

if "%myVariable:~0,1%" == "M" (set myvariable=%myvariable:~1%)

Первая часть «обрезает» первый символ и проверяет, является ли он буквой M, и если да, то сохраняет все, кроме первого символа. Таким образом, вы можете выровнять имена файлов, чтобы обработать их внутри вашего пакетного файла.
Вы также можете «удалить» букву или подстроку с помощью %myVariable:, TX=%, что заменит любое «, TX» вхождение на «ничто», например.

О, это также может помочь удалить любые пробелы в имени файла. Тогда вы можете извлечь "SanFrancisco" без проблем с пробелами;) Хотя имя папки будет без пробелов. Эту проблему можно решить с помощью дальнейших команд rename в конце.

0 голосов
/ 01 мая 2020

Вот мой код, который работал. Однако, если количество символов в префиксах / суффиксах вашего имени файла изменится, это все испортит, и вам придется редактировать код.

@ECHO OFF
SETLOCAL enabledelayedexpansion
FOR %%A in (*.m2v *.mpa) do (
   ECHO file found  %%A
   FOR /F "delims=" %%B in ("%%A") do set fname=%%~nB
   SET folname=!fname:~5,-4!
   ECHO folder name !folname!
   if not exist "!folname!" (
      ECHO Folder !folname! doesn't exist, creating
      MD "!folname!"
   ) else (
      ECHO Folder !folname! exists
   )
   ECHO Moving file %%A to folder !folname!
   MOVE "%%A" "!folname!"
   )
ECHO Finished

PAUSE

Использование SET folname=!fname:~5,-4! позволяет мне обрезать префикс M373 , 5 символов, и, суффикс TX, 4 символа, удаляя запятую и спасая название города, независимо от его длины или количества слов (например, West Palm Beach, FL). Антарес упомянул об этом решении в своем ответе, который работал как шарм.

Но это также заставило меня задуматься

Если количество символов в префиксе изменится, что вполне вероятно, мне придется каждый раз редактировать пакетный файл каждый раз или создайте указанный c пакетный файл для каждого обстоятельства. Не страшно, но и не здорово. Поэтому я согласился с ответом Майкла Хита, который работает безупречно. Я еще не достаточно умен, чтобы точно знать, почему, но я расскажу об этом и выясню. Я многому учусь. Спасибо всем! До изображения После изображения

0 голосов
/ 01 мая 2020
@echo off
setlocal

rem A=Fullpath, B=Name before comma, C=B prefix, D=B without prefix.
for /f "delims=" %%A in ('dir /b *.m2v *.mpa') do (
    for /f "delims=," %%B in ("%%~nA") do (
        for /f "tokens=1,*" %%C in ("%%~B") do (

            if not exist "%%~D\" (
                echo Folder "%%~D" doesn't exist, creating
                md "%%~D"
            )

            if exist "%%~D\" (
                echo Moving file "%%~A" to folder "%%~D\"
                move /y "%%~A" "%%~D\"
            ) else echo Folder "%%~D\" doesn't exist
        )
    )
)

echo Finished
pause

3 for циклы для получения необходимых токенов.

  • 1-й получит полный путь.
  • 2-й, чтобы получить имя перед запятой.
  • 3-й, чтобы получить имя без префикса.

В вложенных циклах for проверьте, существует ли папка, создайте ее, если нет. Затем, если папка существует, переместите файл внутрь.

...