Как извлечь несколько архивов в каждую папку с помощью командной строки WinRAR? - PullRequest
0 голосов
/ 13 апреля 2019

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

Я хочу переместить каждую папку в *Папка 1003 * после распаковки прошла успешно.Но папки, не содержащие архивных файлов, не должны перемещаться пакетным файлом.

До:

C:
│
└─test
    ├─AAAA
    │      XXXX.rar
    │      XXXX.jpg
    │
    ├─BBBB
    │      XXXX.zip
    │      XXXX.jpg
    │
    ├─CCCC(error_file)
    │      XXXX.rar
    │      XXXX.jpg
    │
    ├─DDDD
    │      XXXX.part1.rar
    │      XXXX.part2.rar
    │      XXXX.jpg
    │
    └─EEEE
           XXXX.jpg

После:

C:
│
└─test
    ├─done
    │  │
    │  │
    │  ├─AAAA
    │  │      XXXX.doc
    │  │      XXXX.jpg
    │  │
    │  ├─BBBB
    │  │      XXXX.doc
    │  │      XXXX.jpg
    │  │
    │  └─DDDD
    │         XXXX.doc
    │         XXXX.jpg
    │
    ├─CCCC(error_file)
    │      XXXX.rar
    │      XXXX.jpg
    │
    └─EEEE
           XXXX.jpg


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

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\test"
set "LogExtract=%SourceFolder%\ExtractionLog.txt"
set "LogError=%SourceFolder%\ErrorLog.txt"
set "ArchiveExtracted="

del /Q "%LogExtract%" "%LogError%" 2>nul

for /D %%I in ("%SourceFolder%\*") do (
    if /I not "%%~nxI" == "done" (
        for /F "eol=| delims=" %%J in ('dir "%%I\*.rar" "%%I\*.zip" /A-D-H /B /ON 2^>nul') do (
            if exist "%%I\%%J" (
                echo Extracting "%%I\%%J" ...
                "%ProgramFiles%\WinRAR\WinRAR.exe" x -cfg- -logpfu="%LogExtract%" -or -- "%%I\%%J" "%%I\"
                if errorlevel 1 (
                    set "ArchiveFile=%%I\%%J"
                    >>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
                ) else (
                    echo %%~nJ| %SystemRoot%\System32\findstr.exe /I /R "\.part[0123456789][0123456789]*$" >nul
                    if errorlevel 1 ( del /F "%%I\%%J" ) else for %%# in ("%%~nJ") do del /F /Q "%%I\%%~n#.part*%%~xJ"
                )
            )
        )
        if /I not "%%~nxI" == "done" if not exist "%%I\*.rar" if not exist "%%I\*.zip" move /Y "%%I" "%SourceFolder%\done\"
    )
)


endlocal

1 Ответ

0 голосов
/ 13 апреля 2019

Rar.exe поддерживает только архивы RAR, как описано в верхней части руководства Rar.txt в папке программных файлов WinRAR .WinRAR.exe поддерживает создание архивов RAR и ZIP и извлечение нескольких типов архивов.Поэтому WinRAR.exe используется в приведенном ниже коде пакетного файла.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\Test"
set "LogExtract=%SourceFolder%\ExtractionLog.txt"
set "LogError=%SourceFolder%\ErrorLog.txt"
set "ArchiveExtracted="

del /Q "%LogExtract%" "%LogError%" 2>nul

for /D %%I in ("%SourceFolder%\*") do (
    if /I not "%%~nxI" == "done" (
        for %%J in ("%%I\*.rar" "%%I\*.zip") do (
            if exist "%%J" (
                echo Extracting "%%J" ...
                "%ProgramFiles%\WinRAR\WinRAR.exe" x -cfg- -ibck -logpfu="%LogExtract%" -o+ -y -- "%%J" "%%I\"
                if errorlevel 1 (
                    set "ArchiveFile=%%J"
                    >>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
                ) else (
                    set "#%%~nxI=%%I"
                    set "ArchiveExtracted=1"
                    echo %%~nJ| %SystemRoot%\System32\findstr.exe /I /R "\.part[0123456789][0123456789]*$" >nul
                    if errorlevel 1 ( del /F "%%J" ) else for %%# in ("%%~nJ") do del /F /Q "%%I\%%~n#.part*%%~xJ"
                )
            )
        )
    )
)

if defined ArchiveExtracted (
    md "%SourceFolder%\done" 2>nul
    if exist "%SourceFolder%\done\" (
        for /F "tokens=2 delims==" %%I in ('set #') do move /Y "%%I" "%SourceFolder%\done\"
    )
)

endlocal

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

Для каждого найденного подкаталога, кроме одного с именем done, внутренний FOR ищет не скрытые файлы * .rar и * .zip вподкаталог и выполняет WinRAR.exe для извлечения каждого найденного архивного файла в подкаталог.

WinRAR извлекает каждый архивный файл

  • с сохранением структуры каталогов,
  • с игнорированием стандартной конфигурации,
  • в фоновом режиме, что означает сворачивание в системный трей,
  • с регистрацией извлеченных файлов из RAR архивов в кодировке Unicode (UTF-16Little Endian без BOM) файл журнала извлечения,
  • с перезаписью всех уже существующих файлов,
  • с допуском да для всехзапросы, например, об ошибке.

WinRAR автоматически извлекает все тома многотомного архива.

WinRAR завершает работу со значением больше или равно 1 при ошибке, описанной в справке WinRAR на странице справки Список кодов выхода WinRAR .

Архивимя файла присваивается переменной окружения ArchiveFile в случае не 100% успешного извлечения архивного файла, указанного в результате выхода WinRAR со значением 0, и рядом с выходной строкой сообщения об ошибке выводится код завершения WinRAR и имя файла в файле журнала ошибок.Файл журнала ошибок кодируется в зависимости от кодировки символов и кодовой страницы, определенной командным процессором Windows при запуске пакетной обработки файла.

Переменные среды ErrorLevel и ArchiveFile обозначены двумя знаками процента на каждой стороне, посколькукомандный процессор Windows заменяет уже при разборе всего блока команд перед выполнением внешнего FOR all %% просто %.Команда CALL приводит к повторному анализу командной строки ECHO перед выполнением ECHO , что приводит к замене %Errorlevel% на текущее значение этой переменной среды.как %ArchiveFile% по имени текущего файла архива.

Строка ECHO , такая как echo Error %ErrorLevel% on extracting "%ArchiveFile%" без команды CALL , приведет к замене %ErrorLevel% на текущее значение средыпеременная ErrorLevel перед внешним FOR выполняется вообще, что означает 0 и заменяет %ArchiveFile% пустой строкой, которая, конечно, не будет полезна.

Файл архиваимя присваивается переменной среды ArchiveFile и ссылается как ErrorLevel для обработки также имени файла, например Archive%20!Important!.rar правильно.

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

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

Приведенный выше код не может работать на дисках FAT32 или ExFAT на нескольких файлах * .rar или * .zip в подкаталоге. В этом случае необходимо использовать команду DIR , выполняемую FOR , в отдельном командном процессе, начинающемся с %ComSpec% /C в фоновом режиме, и записывать имена выходных файлов архива. Затем внутренний FOR запускается со списком имен архивных файлов, не измененных во время итераций цикла, что вызвано удалением архивных файлов на дисках FAT32 и ExFAT.

Этот альтернативный пакетный файл также необходим, если архивный файл содержит файлы * .rar или * .zip, которые не следует извлекать случайно, поскольку это может произойти с кодом пакетного файла выше.

Таким образом, этот второй пакетный код более безопасен, чем первый.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\Test"
set "LogExtract=%SourceFolder%\ExtractionLog.txt"
set "LogError=%SourceFolder%\ErrorLog.txt"
set "ArchiveExtracted="

del /Q "%LogExtract%" "%LogError%" 2>nul

for /D %%I in ("%SourceFolder%\*") do (
    if /I not "%%~nxI" == "done" (
        for /F "eol=| delims=" %%J in ('dir "%%I\*.rar" "%%I\*.zip" /A-D-H /B /ON 2^>nul') do (
            if exist "%%I\%%J" (
                echo Extracting "%%I\%%J" ...
                "%ProgramFiles%\WinRAR\WinRAR.exe" x -cfg- -ibck -logpfu="%LogExtract%" -o+ -y -- "%%I\%%J" "%%I\"
                if errorlevel 1 (
                    set "ArchiveFile=%%I\%%J"
                    >>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
                ) else (
                    set "#%%~nxI=%%I"
                    set "ArchiveExtracted=1"
                    echo %%~nJ| %SystemRoot%\System32\findstr.exe /I /R "\.part[0123456789][0123456789]*$" >nul
                    if errorlevel 1 ( del /F "%%I\%%J" ) else for %%# in ("%%~nJ") do del /F /Q "%%I\%%~n#.part*%%~xJ"
                )
            )
        )
    )
)

if defined ArchiveExtracted (
    md "%SourceFolder%\done" 2>nul
    if exist "%SourceFolder%\done\" (
        for /F "tokens=2 delims==" %%I in ('set #') do move /Y "%%I" "%SourceFolder%\done\"
    )
)

endlocal

Примечание: WinRAR версия 5.70 не поддерживает запись имен файлов извлеченных файлов из ZIP архивов в файл журнала извлечения. Это описано в верхней части справочной страницы Переключатель -LOG [fmt] [= name] - записывать имена в файл журнала .

Наконец, если какой-либо архив был успешно извлечен, а затем удален, пакетный файл перемещает все папки, для которых существует переменная среды, начинающаяся с #, в подкаталог done в родительском исходном каталоге. Таким образом, подкаталоги без успешного извлечения хотя бы одного архива игнорируются при перемещении папок, а также подкаталоги, которые не имеют архивного файла. Код может быть проще, если конечный целевой каталог не является подкаталогом родительского исходного каталога.

Еще один вариант, который перемещает папку сразу после завершения извлечения архива. В этом случае необходимо работать с захваченным списком имен подкаталогов, так как список подкаталогов изменяется во время итераций цикла внешнего цикла FOR . FINDSTR используется для фильтрации папки done из списка имен подкаталогов.

Этот пакетный файл ожидает выбора пользователя, чтобы прервать выполнение, выбрав n o автоматически через две секунды. Таким образом, пакетное задание может быть безопасно нарушено пользователем. Этого приглашения можно избежать, запустив пакетный файл с параметром /noprompt.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PromptForBreak="
if /I "%~1" == "/noprompt" set "PromptForBreak=rem"

set "SourceFolder=C:\Test"
set "LogExtract=%SourceFolder%\ExtractionLog.txt"
set "LogError=%SourceFolder%\ErrorLog.txt"

del /Q "%LogExtract%" "%LogError%" 2>nul

for /F "eol=| delims=" %%I in ('dir "%SourceFolder%\*" /AD-H /B /ON 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /C:done') do (
    set "ArchiveExtracted="
    for /F "eol=| delims=" %%J in ('dir "%SourceFolder%\%%I\*.rar" "%SourceFolder%\%%I\*.zip" /A-D-H /B /ON 2^>nul') do (
        if exist "%SourceFolder%\%%I\%%J" (
            echo Extracting "%SourceFolder%\%%I\%%J" ...
            "%ProgramFiles%\WinRAR\WinRAR.exe" x -cfg- -ibck -logpfu="%LogExtract%" -o+ -y -- "%SourceFolder%\%%I\%%J" "%SourceFolder%\%%I\"
            if errorlevel 1 (
                set "ArchiveFile=%SourceFolder%\%%I\%%J"
                >>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
            ) else (
                set "ArchiveExtracted=1"
                echo %%~nJ| %SystemRoot%\System32\findstr.exe /I /R "\.part[0123456789][0123456789]*$" >nul
                if errorlevel 1 ( del /F "%SourceFolder%\%%I\%%J" ) else for %%# in ("%%~nJ") do del /F /Q "%SourceFolder%\%%I\%%~n#.part*%%~xJ"
            )
        )
    )
    if defined ArchiveExtracted (
        md "%SourceFolder%\done" 2>nul
        if exist "%SourceFolder%\done\" move /Y "%SourceFolder%\%%I" "%SourceFolder%\done\"
        %PromptForBreak% %SystemRoot%\System32\choice.exe /C NY /N /T 2 /D N /M "Break execution [N/Y]? "
        %PromptForBreak% if errorlevel 2 goto EndBatch
    )
)

:EndBatch
endlocal

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

  • call /?
  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • if /?
  • md /?
  • move /?
  • set /?
  • setlocal /?
...