I want to extract ZIP and RAR archives existing in each folder to the respective folder at the command line. Furthermore, I want to delete the original compressed file only if there is no error during decompression. If there is an error on extracting an archive, the archive file name should be written to an error log file and extraction process should continue with the next archive file(s).
I want to move every folder to done
folder after the decompression is successful. But folders not containing any archive file should not be moved by the batch file.
Before:
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
After:
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
The following code taken from Mofi's answer from initial version of the question and adapted by me did not work.
@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
Rar.exe
supports only RAR archives as documented at top of its manualRar.txt
in program files folder of WinRAR.WinRAR.exe
supports creation of RAR and ZIP archives and extraction of multiple archive types. ThereforeWinRAR.exe
is used in batch file code below.After definition of parent source folder and deletion of perhaps already existing log files from a previous execution the outer FOR searches in specified source folder for non-hidden subdirectories.
For each found subdirectory except the one with name
done
the inner FOR searches for non-hidden *.rar and *.zip files in the subdirectory and executesWinRAR.exe
to extract each found archive file into the subdirectory.WinRAR extracts each archive file
WinRAR automatically extracts all volumes of a multi-volume archive.
WinRAR exits with a value greater or equal
1
on an error as documented in help of WinRAR on help page List of WinRAR exit codes.The archive file name is assigned to environment variable
ArchiveFile
in case of a not 100% successful extraction of an archive file indicated by exit of WinRAR with value0
and next an error message line is output writing exit code of WinRAR and the file name into the error log file. The error log file is encoded depending on character encoding and code page defined by Windows command processor on starting batch file processing.The environment variables
ErrorLevel
andArchiveFile
are referenced with two percent signs on each side because of Windows command processor replaces already on parsing entire command block before executing outer FOR all%%
by just%
. The command CALL results in a second parsing of the ECHO command line before executing ECHO which results in replacing%Errorlevel%
by current value of this environment variable as well as%ArchiveFile%
by current archive file name.An ECHO line like
echo Error %ErrorLevel% on extracting "%ArchiveFile%"
without command CALL would result in replacing%ErrorLevel%
by current value of environment variableErrorLevel
before outer FOR is executed at all which means with0
and would replace%ArchiveFile%
by an empty string which of course would not be helpful.The archive file name is assigned to environment variable
ArchiveFile
and referenced likeErrorLevel
to handle also a file name likeArchive%20!Important!.rar
correct.On an error on a multi-volume archive none of the RAR archive parts are deleted resulting in the approach of extracting all volumes of the multi-volume archive multiple times with each part of multi-volume archive file written into the error log file.
The archive file is deleted on a successful extraction of a single archive file respectively all parts of a multi-volume archive are deleted on successful extraction of a multi-volume archive. Additionally an environment variable is set with
#
plus subdirectory name as environment variable name and full path of subdirectory as value to remember which subdirectories contained at least one successfully extracted archive to move it later. It is required for this simple method that no subdirectory name contains an equal sign.The above code could not work on FAT32 or ExFAT drives on more than one *.rar or *.zip file in a subdirectory. In this case it is necessary to use command DIR executed by FOR in a separate command process started with
%ComSpec% /C
in background and capture the output archive file names. Then the inner FOR runs with a list of archive file names not modified during the loop iterations as caused by deletion of the archive files on FAT32 and ExFAT drives.This alternate batch file is also needed if an archive file contains itself *.rar or *.zip files which should not be extracted by chance as it can happen with the batch file code above.
So this second batch code is more safe than the first one.
Note: WinRAR version 5.70 does not support writing the file names of extracted files from ZIP archives to the extraction log file. This is documented at top of help page Switch -LOG[fmt][=name] - write names to log file.
Finally, if any archive was successfully extracted and then deleted, the batch file moves all folders for which an environment variable starting with
#
exists into subdirectorydone
in parent source directory. So subdirectories with no successful extraction of at least one archive are ignored on folder movement as well as subdirectories which have no archive file. The code could be easier if the final destination directory is not a subdirectory of the parent source directory.One more variant which moves a folder immediately after archive extraction(s) finished. It is necessary in this case to work with a captured list of subdirectory names as the list of subdirectories changes during loop iterations of outer FOR loop. FINDSTR is used to filter out folder
done
from list of subdirectory names.This batch file waits for a user choice to break execution with choosing no automatically after two seconds. So the batch job can be safely broken by a user. This prompt can be avoided by starting the batch file with parameter
/noprompt
.For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
del /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
if /?
md /?
move /?
set /?
setlocal /?