tags:

views:

208

answers:

3

I have a bash shell script that unzips a zip file, and manipulates the resulting files. Because of the process, I expect all the content I am interested to be within a single folder like so:

file.zip  
  /file  
    /contentFolder1
    /contentFolder2
    stuff1.txt
    stuff2.txt
    ...

I've noticed users on Windows typically don't create a sub folder but instead submit an exploding zip file that looks like:

file.zip  
    /contentFolder1
    /contentFolder2
    stuff1.txt
    stuff2.txt
    ...

How can I detect these exploding zips, so that I may handle them accordingly? Is it possible without unzipping the file first?

A: 

I wouldn't try to detect it. I'd just force unzip to do what I want. With InfoZip:

$ unzip -j -d unzip-output-dir FileFromUntrustedSource.zip

-j makes it ignore any directory structure within the file, and -d tells it to put files in a particular directory, creating it if necessary.

If there are two files with the same name but in different subdirectories, the above command will make unzip ask if you want to overwrite the first with the second. You can add -o to force it to overwrite without asking, or -f to only overwrite if the second file is newer.

Warren Young
+1  A: 

Unzip to a directory first, and then remove the extra layer if the zip is not a bomb.

tempdir=`mktemp -d`
unzip -d $tempdir file.zip
if [ $(ls $tempdir | wc -l) = 1 ]; then
        mv $tempdir/* .
        rmdir $tempdir
else
        mv $tempdir file
fi
ephemient
+1  A: 

If you want to check, unzip -l will print the contents of the zip file without extracting them. You'll have to massage the output a bit, though, since it's printing all sorts of additional crud.

jk
You could also control the output with zipinfo -1 a bit more, but it looks arbitrarily deep, so I'd have to parse each line...
Andrew Austin
No, you just need to match that all the lines start with the same thing (the directory name) followed by a slash. And that's easily done, say, with `sed s/([^/]*)\/\1/ | sort -u` and checking that you only get one line of output. (Well, that `sed` command probably doesn't work exactly as written, but you get the idea.)
jk
You probably mean something more like `sed 's:[/\\].*::'`, but the idea is sound.
ephemient