Пакетное создание папки с тем же именем файла - PullRequest
0 голосов
/ 23 февраля 2020

Я использую этот код для создания папок и унификации файлов с одинаковыми именами, получается, что некоторые файлы работали, как в случае с 3D Pool, но в других случаях файлы (Диск 1 из 2), ( Диск 2 из 2) не работал, может помочь?

@echo off
setlocal

set "basename=."
for /F "tokens=1* delims=." %%a in ('dir /B /A-D ^| sort /R') do (
   set "filename=%%a"
   setlocal EnableDelayedExpansion
   for /F "delims=" %%c in ("!basename!") do if "!filename:%%c=!" equ "!filename!" (
      set "basename=!filename!"
      md "!basename!"
   )
   move "!filename!.%%b" "!basename!"
   for /F "delims=" %%c in ("!basename!") do (
      endlocal
      set "basename=%%c
   )
)

Моя папка struture с файлами:

3D Pool (1989)(Firebird Software)(Disk 1 of 2).dsk
3D Pool (1989)(Firebird Software)(Disk 2 of 2).dsk
3D Pool (1989)(Firebird Software).dsk
3D Pool (1989)(Firebird Software)[cr Steel McKraken - Exocet].dsk
5th Axis, The (1985)(Loriciels)(fr).dsk
5th Axis, The (1985)(Loriciels)(fr)[a].dsk
5th Axis, The (1985)(Loriciels).dsk
Zolyx (1988)(Firebird Software).dsk
Zolyx (1988)(Firebird Software)[t].dsk
Zombi (1990)(Ubisoft)(fr)(Disk 1 of 2).dsk
Zombi (1990)(Ubisoft)(fr)(Disk 1 of 2)[6128 Version].dsk
Zombi (1990)(Ubisoft)(fr)(Disk 2 of 2).dsk
Zombi (1990)(Ubisoft)(fr)(Disk 2 of 2)[6128 Version].dsk
Zombi (1990)(Ubisoft)(fr)[464 Version].dsk

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

3D Pool (1989)(Firebird Software)
3D Pool (1989)(Firebird Software)[cr Steel McKraken - Exocet]
5th Axis, The (1985)(Loriciels)
Zolyx (1988)(Firebird Software)
Zolyx (1988)(Firebird Software)[t]
Zombi (1990)(Ubisoft)(fr)(Disk 1 of 2)
Zombi (1990)(Ubisoft)(fr)(Disk 1 of 2)[6128 Version]
Zombi (1990)(Ubisoft)(fr)(Disk 2 of 2)
Zombi (1990)(Ubisoft)(fr)(Disk 2 of 2)[6128 Version]
Zombi (1990)(Ubisoft)(fr)[464 Version]

я хотел бы, чтобы пакет помещал файлы в папку по именам, оставляя ее максимально чистой:

3D Pool (1989)(Firebird Software)
   3D Pool (1989)(Firebird Software)(Disk 1 of 2).dsk
   3D Pool (1989)(Firebird Software)(Disk 2 of 2).dsk
   3D Pool (1989)(Firebird Software).dsk
   3D Pool (1989)(Firebird Software)[cr Steel McKraken - Exocet].dsk
5th Axis, The (1985)(Loriciels)
   5th Axis, The (1985)(Loriciels)(fr).dsk
   5th Axis, The (1985)(Loriciels)(fr)[a].dsk
   5th Axis, The (1985)(Loriciels).dsk
Zolyx (1988)(Firebird Software)
   Zolyx (1988)(Firebird Software).dsk
   Zolyx (1988)(Firebird Software)[t].dsk
Zombi (1990)(Ubisoft)(fr)
   Zombi (1990)(Ubisoft)(fr)(Disk 1 of 2).dsk
   Zombi (1990)(Ubisoft)(fr)(Disk 1 of 2)[6128 Version].dsk
   Zombi (1990)(Ubisoft)(fr)(Disk 2 of 2).dsk
   Zombi (1990)(Ubisoft)(fr)(Disk 2 of 2)[6128 Version].dsk
   Zombi (1990)(Ubisoft)(fr)[464 Version].dsk

возможно ли это сделать?

Ответы [ 3 ]

0 голосов
/ 24 февраля 2020

Mofi, большое спасибо за помощь и объяснение команд, у меня есть некоторые проблемы

то, что случилось, некоторые игры не ведут себя таким образом, это был случай игр

20000 Lieus sous les Mers (1988)(Coktel Vision)(fr)(Disk 1 of 2).dsk
20000 Lieus sous les Mers (1988)(Coktel Vision)(fr)(Disk 2 of 2).dsk

они не были в одной папке, независимо от списка папок (Диск x of y):

20000 Lieus sous les Mers (1988)(Coktel Vision)(fr)(Disk 1 of 2)
20000 Lieus sous les Mers (1988)(Coktel Vision)(fr)(Disk 2 of 2)
3 Guerra Mundial (1989)(Pactum)(es)(Disk 1 of 2)
3 Guerra Mundial (1989)(Pactum)(es)(Disk 2 of 2)
A la Conquete de l'Orthographe (1991)(Generation 5)(fr)(Disk 1 of 2)
A la Conquete de l'Orthographe (1991)(Generation 5)(fr)(Disk 2 of 2)
A la Pursuite de Carmen Sandiego dans le Monde (1990)(Broderbund Software)(fr)(Disk 1 of 2)
A la Pursuite de Carmen Sandiego dans le Monde (1990)(Broderbund Software)(fr)(Disk 2 of 2)
Zap 't' Balls - The Advanced Edition (1992)(Elmsoft Game-Service)(Disk 1 of 2)
Zap 't' Balls - The Advanced Edition (1992)(Elmsoft Game-Service)(Disk 2 of 2)

полный список папок: https://pastebin.com/UmZFR3mb

Я хотел бы понять, почему эти файлы не следовали шаблону файла bat

0 голосов
/ 24 февраля 2020
@echo off

for %%A in (*.dsk) do (
    for /f "tokens=1-3 delims=()" %%B in ("%%~A") do (
        if not exist "%%~B(%%~C)(%%~D)" md "%%~B(%%~C)(%%~D)"
        move /y "%%~A" "%%~B(%%~C)(%%~D)\" >nul
    )
)

Использует шаблон name (year)(publisher) для имен папок, взятых из имен файлов.

0 голосов
/ 24 февраля 2020

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

@echo off
if "%~1" == "" (pushd "%~dp0") else (
    pushd "%~1"
    if errorlevel 1 (
        echo ERROR: Directory "%~1" does not exist.
        echo/
        pause
        exit
    )
)

setlocal EnableExtensions DisableDelayedExpansion
set "FolderName=\"

for /F "eol=| delims=" %%I in ('dir /A-D /B /O-N 2^>nul') do if not "%%~fI" == "%~f0" (
    for /F "eol=| tokens=1 delims=[]" %%J in ("%%~nI") do (
        set "FileName=%%J"
        set "FullName=%%I"
        setlocal EnableDelayedExpansion
        set "DiskAddon=!FileName:*(Disk =(Disk !"
        if not "!DiskAddon!" == "!FileName!" for /F "delims=" %%V in ("!DiskAddon!") do set "FileName=!FileName:%%V=!"
        for /F "eol=| delims=" %%K in ("!FolderName!") do (
            if "!FileName:%%K=!" == "!FileName!" (
                md "!FileName!" 2>nul
                move /Y "!FullName!" "!FileName!\"
                for /F "eol=| delims=" %%V in ("!FileName!") do (
                    endlocal
                    set "FolderName=%%V"
                )
            ) else (
                move /Y "!FullName!" "!FolderName!\"
                endlocal
            )
        )
    )
)

endlocal
popd

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

Переменная среды FolderName хранит имя последней созданной папки в зависимости от имени файла. Переменная среды FolderName определена с недопустимым именем \, чтобы всегда работать в true ветви самого внутреннего IF условия в первом файле.

Первый FOR выполняется в фоновом режиме еще один командный процесс, запущенный с %ComSpec% /c, и командная строка между ' добавляется в качестве дополнительных аргументов. Выполняется так: Windows установлен в C:\Windows:

C:\Windows\System32\cmd.exe /c dir /A-D /B /O-N 2>nul

Команда DIR , выполняемая запущенным фоновым процессом обработки команды, обрабатывает STDOUT (стандартный вывод ) фонового командного процесса

  • только имена файлов из-за опции /A-D (атрибут не каталог)
  • в голом формате, что означает просто имя файла с расширением файла, но без путь к файлу из-за опции /B
  • в обратном порядке по имени из-за /O-N
  • всех файлов в текущем каталоге, соответствующих шаблону подстановочных знаков по умолчанию *.

Здесь необходим обратный порядок, чтобы сначала выводить более короткие имена файлов, соответственно те, которые выводятся с [...], а затем с (Disk x of y).

Возможно, что файл вообще не найден. В этом случае сообщение об ошибке будет выдано DIR для обработки STDERR (стандартная ошибка). Это не важное сообщение об ошибке подавляется путем перенаправления его на устройство NUL . FOR l oop ничего не делает для файлов, найденных в указанном каталоге.

Прочтите статью Microsoft о Использование операторов перенаправления команд для объяснения 2>nul , Оператор перенаправления > должен быть экранирован с помощью символа вставки ^ в FOR командной строке, чтобы интерпретироваться как литеральный символ, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR который выполняет встроенную dir командную строку в отдельном командном процессе, запущенном в фоновом режиме.

FOR с используемой опцией /F и командной строкой, заключенной в ', захватывает все вывод для обработки STDOUT запущенного фонового командного процесса и построчно обрабатывает этот вывод после запуска cmd.exe после завершения выполнения командной строки.

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

FOR будет разбивать каждую строку на подстроки по умолчанию с использованием обычного пробела и горизонтальной табуляции в качестве разделителя строк и будет назначать только первая разделенная пробелами / табуляцией подстрока для указанной переменной l oop I. Такое поведение разделения строк здесь нежелательно, поскольку имена файлов могут содержать один или несколько пробелов. По этой причине пустой список разделителей определяется с опцией delims=, чтобы полностью отключить поведение разделения строк.

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

Таким образом, каждое имя файла с расширением файла полностью присваивается переменной l oop один за другим I для дальнейшей обработки.

Пакетный файл, обрабатываемый в данный момент cmd.exe, игнорируется при обработке имен файлов из-за условия IF в первой командной строке FOR .

Следующая FOR обрабатывает только имя файла без расширения файла как строку. Опции eol=| tokens=1 delims=[] предназначены для разбиения имени файла на подстроки с использованием квадратных скобок в качестве разделителей с первой подстрокой, назначенной указанной переменной l oop J, и без игнорирования имен файлов, начинающихся с ;. Это необходимо для получения имени файла, например 3D Pool (1989)(Firebird Software)[cr Steel McKraken - Exocet].dsk, просто 3D Pool (1989)(Firebird Software), назначенного для l oop переменная J для дальнейшей обработки.

Переменные не работают так, как ожидается описывает что командный процессор Windows заменяет все %variable% в командном блоке, начиная с ( и заканчивая сопоставлением ) по текущему значению переменной среды, прежде чем команда будет выполнена с использованием командного блока. Это означает, что требуется отложенное расширение , которое нельзя включить выше FOR l oop, поскольку в противном случае каждый ! в имени файла будет интерпретироваться также как начало / конец среды ссылка на переменную расширена с задержкой на выполнение. По этой причине отложенное расширение включено и отключено внутри l oop.
. Прочитайте этот ответ , чтобы узнать подробнее о командах SETLOCAL и ENDLOCAL .

Переменная среды DiskAddon определяется либо с частью (Disk x of y) в конце имени файла, если строка (Disk находится где-то в имени файла, либо с неизмененным именем файла, если не содержит (Disk в all.

Таким образом, если строка, присвоенная DiskAddon, отличается от строки имени файла, строка (Disk x of y) также удаляется из имени файла с использованием подстановки с расширенной строкой с задержкой. Текущая строка, назначенная для DiskAddon, должна быть временно назначена для переменной al oop, чтобы иметь возможность использовать эту строку в отложенной подстановке расширенной строки. Невозможно указать задержанную ссылку на расширенную переменную среды внутри отложенной замены расширенной переменной среды.

Имя текущей папки должно быть временно назначено также переменной oop, чтобы иметь возможность использовать эту строку в отложенная замена расширенной строки при следующем IF условии. Таким образом, следующий FOR предназначен только для назначения имени текущей папки, назначенного переменной окружения FolderName переменной l oop K.

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

Поэтому папка создается с текущим (усеченным) именем файла с подавлением сообщения об ошибке с перенаправлением на устройство NUL на уже существующей папке и перемещая текущий файл в эту папку. Далее необходимо отключить отложенное расширение и восстановить предыдущую среду. Но необходимо передать имя папки только что созданной папки в предыдущую среду. Итак, еще раз FOR l oop используется с именем текущей папки или усеченным именем файла, назначенным для l oop variable V, чтобы получить имя папки, назначенное переменной среды FolderName в предыдущем environment.

В противном случае текущий файл перемещается в ту же папку, что и предыдущий файл, перед отключением отложенного расширения и восстановлением предыдущей среды.

Наконец, пакетный файл восстанавливает исходную среду, а также исходный текущий каталог.


Здесь также есть альтернативное решение, использующее подпрограмму, которая упрощает подстановку строк, поскольку в командном блоке нет командной строки.

@echo off
if "%~1" == "" (pushd "%~dp0") else (
    pushd "%~1"
    if errorlevel 1 (
        echo ERROR: Directory "%~1" does not exist.
        echo/
        pause
        exit
    )
)

setlocal EnableExtensions DisableDelayedExpansion
set "FolderName=\"
for /F "eol=| delims=" %%I in ('dir /A-D /B /O-N 2^>nul') do if not "%%~fI" == "%~f0" call :ProcessFile "%%I"
goto EndBatch

:ProcessFile
for /F "eol=| tokens=1 delims=[]" %%J in ("%~n1") do set "FileName=%%J"
setlocal EnableDelayedExpansion
set "DiskAddon=!FileName:*(Disk =(Disk !"
if not "!DiskAddon!" == "!FileName!" set "FileName=!FileName:%DiskAddon%=!"
if not "!FileName:%FolderName%=!" == "!FileName!" endlocal & goto MoveFile
endlocal & set "FolderName=%FileName%"
md "%FolderName%" 2>nul
:MoveFile
move /Y %1 "%FolderName%\"
goto :EOF

:EndBatch
endlocal
popd

См. одну строку с несколькими командами, использующими Windows пакетный файл для объяснения оператора &, использованным в этом пакетном файле два раза, чтобы избежать использования командного блока.


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

  • call /? ... объясняет %~dp0, %~f0, %1, %~1, %~n1
  • dir /?
  • echo /?
  • endlocal /?
  • exit /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • move /?
  • pause /?
  • popd /?
  • pushd /?
  • set /?
  • setlocal /?

PS: использование сценария PowerShell для всей задачи будет намного лучше. PowerShell поддерживает встроенные строковые функции, такие как поиск строки в строке или изменение строки с помощью регулярного выражения для получения базового имени файла. Командный процессор Windows, выполняющий пакетный файл, предназначен для выполнения команд и исполняемых файлов, а не для работы со строками, необходимыми для этой задачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...