Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Given there is a secret file deep inside a nested ZIP file, i.e. a zip file inside a zip file inside a zip file, etc...

The zip files are named 1.zip , 2.zip , 3.zip , etc...

We don't know how deep the zip files are nested, but it may be thousands.

What would be the easiest way to loop through all of them up until the last one to read the secret file?

My initial approach would have been to call unzip recursively, but my Bash skills are limited. What are your ideas to solve this?

so 1.zip is inside 2.zip which in turn is inside 3.zip and so on? Does a zip file have more than 1 file inside? If yes could it be a non zip file? all the zip files have the .zip extension? CristiFati Dec 10, 2015 at 18:28 @CristiFati: Each Zip file contains exactly one zip file: 1.zip contains 2.zip, 2.zip contains 3.zip and so on AdHominem Dec 10, 2015 at 18:40 Well I guess the zip quine is a special case, but not that relevant when the goal is to ultimately hide some data inside the zip queue. AdHominem Dec 11, 2015 at 8:09 function extract(){ unzip $1 -d ${1/.zip/} && eval $2 && cd ${1/.zip/} for zip in `find . -maxdepth 1 -iname *.zip`; do extract $zip 'rm $1' extract '1.zip' This helped me with my nested zip case. Though I should note that I needed to (1) Modify unzip $1 -d ${1/.zip/} && eval $2 && cd ${1/.zip/} to be three separate lines, (2) Put *.zip in single quotes, (3) Add cd .. after the for loop. Also, this doesn't handle zips files that are in subdirectories of the parent zip. vinays84 Jan 20, 2021 at 17:35

Checkout this java based utility nzip for nested zips.

Extracting and compressing nested zips can be done easily using following commands:

java -jar nzip.jar -c list -s readme.zip 
java -jar nzip.jar -c extract -s "C:\project\readme.zip" -t readme 
java -jar nzip.jar -c compress -s readme -t "C:\project\readme.zip" 
PS. I am the author and will be happy to fix any bugs quickly.

Here is a solution for windows assuming 7zip is installed in the default location.

@echo off
Setlocal EnableDelayedExpansion
Set source=%1
Set SELF=%~dpnx0
For %%Z in (!source!) do (
    set FILENAME=%%~nxZ
set FILENAME=%FILENAME:"=%
"%PROGRAMFILES%\7-zip\7z.exe" x -o* -y "%FILENAME%"
REM DEL "%FILENAME%"
rem " This is just to satisfy stackoverflow code formatting!
For %%Z in (!source!) do (
    set FILENAME=%%~nZ
for %%a in (zip rar jar z bz2 gz gzip tgz tar lha iso wim cab rpm deb) do (
    forfiles /P ^"%FILENAME%^" /S /M *.%%a /C "cmd /c if @isdir==FALSE \"%SELF%\" @path"

This has been adapted from here https://social.technet.microsoft.com/Forums/ie/en-US/ccd7172b-85e3-4b4a-ad93-5902e0abd903/batch-file-extracting-all-files-from-nested-archives?forum=ITCG

Notes:

  • The only way to do variable modification using the ~ modifiers is to use a dummy for..in loop. If there is a better way please edit.
  • ~nx modifies the variable to make it a full path+file name.
  • ~dpnx also does the same thing to %0 i.e. gets the full path and filename of the script.
  • -o* in the 7zip command line allows 7zip to create folder names without the .zip extension like it does when extracting with a right click in the gui.
  • ~n modifies the variable to make it a filename without an extension. i.e. drops the .zip
  • Note that the escape character (for quotes) in FORFILES /P is ^ (caret) while for the CMD /C it is \. This ensures that it handles path and filenames with spaces also recursively without any problem.
  • You can remove the REM from the DEL statement if you want the zip file to be deleted after unzipping.
  • I know that this question is a bit old but if someone stumbles upon similar problem then this bash script might be useful.
    This script unzips recursively and retains the original folder hierarchy structure inside zip file instead of unzipping everything into the current directory.
    This script also handles a bit pathological cases in which there are many zip files within zips or folders alternately in one zip file.

    Iterating over files and folders based on this tutorial to avoid problems with white spaces, NULs, newline delimiters, etc.
    http://mywiki.wooledge.org/BashFAQ/001

    #!/bin/bash
    function extractZipsInCurrentDirLevel() {
      find . -mindepth 1 -maxdepth 1 -type f -iname '*.zip' -print0 | 
      while IFS= read -r -d '' zipfile; 
        unzip "${zipfile}" -d "${zipfile%.*}"; # %.* removes file extension
        rm "${zipfile}";
    function extractZipsRecursively() {
      extractZipsInCurrentDirLevel; # this can generate new folders after unzipping
      find . -mindepth 1 -maxdepth 1 -type d -print0 | 
      while IFS= read -r -d '' folder; 
      do # call this function recursively for every child subdirectory
        cd "${folder}"
        extractZipsRecursively;
        cd ..
    extractZipsRecursively; # main entry function call of shell script
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.