On several occasions, say I have a.zip, which unzips into a/* itself.

However, often there are zip files which spill all their contents into the current directory. This requires me to manually create a director a and unzip into it.

But if as a policy I always create a directory, and the zip turns out to be of the first kind, my structure looks like a/a/* which is not ideal.

Is there a way to unzip a.zip into a/* irrespective of its type among the two types which I described above?

2 Answers 2


Try this:

has_parent=$(unzip -l "$archive" | tail -n+4 | head -n-2 | awk '{split($NF,a,"/");print a[1]}' | sort -u | wc -l)
if test "$has_parent" -eq 1; then
  unzip $archive
  dir="./$(basename ${archive%%.zip})"
  mkdir "$dir"
  unzip -d "$dir" $archive

If using zipinfo you can squeeze $has_parent line to this:

has_parent=$(zipinfo -1 "$archive" | awk '{split($NF,a,"/");print a[1]}' | sort -u | wc -l)

Idea is simple - if there are several files on the root level of the archive it obviously will trash your current directory if you unpack it, therefore you must create a parent directory beforehand and unpack files in there. Otherwise if all the files in the archive have the same parent then it's ok to unpack in the current dir.


Use zipinfo for displaying, zip contents.:

$ zipinfo -1 a.zip

Though, this probably doesn't answer your question if you are looking for an automation answer.

Edit: What you could do is check each line of output from zipinfo for a forward slash character. If there is a line missing the character, you know that it is located at the root of the zip file.

Unfortunately, I can't think of exactly how to do this of the top of my head. Not sure if it will work, but here is an untested command:

$ for X in $(zipinfo -1 a.zip); do $(echo "${X}" | grep "/"); if test "$?" -gt "0"; then MKROOT=1; fi; done
$ if test "${MKROOT}" -gt "0"; then mkdir "a"; cd "a"; unzip "../a.zip"; else unzip "a.zip"; fi

Edit: Mark Perryman's suggestion is probably better. I just realized that my command checks if files are contained in sub-folders, but it doesn't check if all are contained under the same root folder.

  • 1
    zipinfo -1 a.zip | sed -r 's#([^/]+/).*#\1#' | sort -u | wc -l will output 1 if all paths have the same leading directory. Commented Nov 28, 2017 at 10:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .