I'm trying to make a script that will unzip a password protected file, the password being the name of the file that I will get when unzipping

Eg.

file1.zip contains file2.zip and it's password is file2.

file2.zip contains file3.zip and it's password is file3

How do I unzip file1.zip, and read the name of file2.zip so it can be entered in the script?

Here's a screenshot of what I meant, I just need bash to read that output in order to know the new password (In this case the password is 13811).

Here's what I've done so far

    #!/bin/bash

    echo First zip name:
    read firstfile


    pw=$(zipinfo -1 $firstfile | cut -d. -f1)
    nextfile=$(zipinfo -1 $firstfile)
    unzip -P $pw $firstfile

    rm $firstfile
    nextfile=$firstfile

Now how can I make it do the loop?

  • Is it just one file in the initial zipped file and so just file2.zip in file1.zip? – Raman Sailopal Aug 8 at 12:33
  • Yes, every zip contains a single zip with more than 100 zips in total. – molinskeh Aug 8 at 12:39
  • So this is a zip file that's nested 100 levels deep? Or it's one zip file that contains 100 zip files? – Jeff Schaller Aug 8 at 13:30
  • (or you have 100 zip files to unzip in the current directory)? – Jeff Schaller Aug 8 at 13:32
  • 1
    Is fcrackzip in-scope? If so, don't even bother to ask the user for the file passwords :) – Christopher Schultz Aug 8 at 20:55
up vote 8 down vote accepted

If you don't have and cannot install zipinfo for any reason, you can imitate it by using unzip with -Z option. To list the contents of the zip use unzip -Z1:

pw="$(unzip -Z1 file1.zip | cut -f1 -d'.')" 
unzip -P "$pw" file1.zip

Put it to a loop:

zipfile="file1.zip"
while unzip -Z1 "$zipfile" | head -n1 | grep "\.zip$"; do
    next_zipfile="$(unzip -Z1 "$zipfile" | head -n1)"
    unzip -P "${next_zipfile%.*}" "$zipfile"
    zipfile="$next_zipfile"
done

or a recursive function:

unzip_all() {
    zipfile="$1"
    next_zipfile="$(unzip -Z1 "$zipfile" | head -n1)"
    if echo "$next_zipfile" | grep "\.zip$"; then
        unzip -P "${next_zipfile%%.*}" "$zipfile"
        unzip_all "$next_zipfile"
    fi
}
unzip_all "file1.zip"

-Z zipinfo(1) mode. If the first option on the command line is -Z, the remaining options are taken to be zipinfo(1) options. See the appropriate manual page for a description of these options.

-1 : list filenames only, one per line. This option excludes all others; headers, trailers and zipfile comments are never printed. It is intended for use in Unix shell scripts.

  • Awesome it worked, thank you! Btw in the loop function, why did you grep "\.zip$", head -n1 spits out the same output every time with or without grep. Also what does %%.* mean on the 4th line of the loop function? – molinskeh Aug 8 at 13:47
  • 1
    actually %%.* should be %.*, I changed that. See stackoverflow.com/a/965072/7365127 for explanation what it does. – RoVo Aug 8 at 13:52
  • | grep "\.zip$" gives same output, but returns true when .zip found and false when not found => As I use it in the if or while statement, this return value will stop the function when ".zip" is not found anymore. – RoVo Aug 8 at 13:54

Ask zipinfo for the filename listed in the zip file, then capture it for the password. Use that password to unzip the file:

pw=$(zipinfo -1 file1.zip | cut -d. -f1)
unzip -P "$pw" file1.zip

Note that the flag to zipinfo is a one not an ell.

Borrowing liberally from Gilles' answer to a similar question, here's a bash loop that will extract a password-protected nested zip file until there are no more zip files:

shopt -s nullglob
while set -- *.zip; [ $# -eq 1 ]
do 
  unzippw "$1" && rm -- "$1"
done

Where I've defined the function unzippw as a wrapper for the zipinfo and unzip commands above:

unzippw ()
{
    local pw=$(zipinfo -1 "$1" | cut -d. -f1)
    unzip -P "$pw" "$1"
}
  • 1
    +1 for zipinfo, didn't know this :-> – RoVo Aug 8 at 12:57
  • It's part of the unzip package (RPM example, DEB example), so I felt safe suggesting it. – Jeff Schaller Aug 8 at 13:09
  • Thanks for the reply, I think I got the logic now, not sure how to continue the loop though – molinskeh Aug 8 at 13:28
  • 1
    That loop will only keep the files extracted at the very end which is probably what OP wants, but it's worth mentioning. – RoVo Aug 8 at 13:56
  • It won’t even keep the last zip file! – Jeff Schaller Aug 8 at 13:57

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.