7

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?

10
  • Is it just one file in the initial zipped file and so just file2.zip in file1.zip? Aug 8, 2018 at 12:33
  • Yes, every zip contains a single zip with more than 100 zips in total.
    – molinskeh
    Aug 8, 2018 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, 2018 at 13:30
  • (or you have 100 zip files to unzip in the current directory)?
    – Jeff Schaller
    Aug 8, 2018 at 13:32
  • 1
    Is fcrackzip in-scope? If so, don't even bother to ask the user for the file passwords :) Aug 8, 2018 at 20:55

2 Answers 2

9

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.

3
  • 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, 2018 at 13:47
  • 1
    actually %%.* should be %.*, I changed that. See stackoverflow.com/a/965072/7365127 for explanation what it does.
    – pLumo
    Aug 8, 2018 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.
    – pLumo
    Aug 8, 2018 at 13:54
8

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"
}
5
  • 1
    +1 for zipinfo, didn't know this :->
    – pLumo
    Aug 8, 2018 at 12:57
  • It's part of the unzip package (RPM example, DEB example), so I felt safe suggesting it.
    – Jeff Schaller
    Aug 8, 2018 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, 2018 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.
    – pLumo
    Aug 8, 2018 at 13:56
  • It won’t even keep the last zip file!
    – Jeff Schaller
    Aug 8, 2018 at 13:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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