Find all zips, and unzip in place - Unix [closed]
Asked Answered
V

4

17

I have been trying for some time and believe I am fairly close to this, but I am fairly new to Unix so have been finding this difficult.

I have a folder, containing many folders, some of which have zip files in them, some which don't. I am trying to unzip all of the zip files in any sub directories in place.

For example I have:

files/A/something.java

files/B/somezipfile.zip

files/C/someotherfile.zip

files/D/AnotherZipFile.zip

I would like to unzip them (assuming the zips contain just .java files), to have a result like: files/A/something.java

files/B/javafile.java

files/C/someotherfilefromzip.java

files/D/Anotherfile.java

I don't mind if the ZIP files remain or are deleted after unzipping, either is fine.

What I have tried so far.

  1. I expected I could use piping, which I am new to, like this:

     find . -name *.zip | unzip
    

    This doesn't work.

  2. I spent some time searching, the closest I got using a solution online is:

     find . -name '*.zip' -exec unzip '{}' ';'
    

    This unzips, but unzips them into the current working directory, I wanted them to unzip in place. I also don't understand this command which I would like to as I am trying to learn.

Varnado answered 11/2, 2013 at 13:36 Comment(0)
T
56
find . -name '*.zip' -exec sh -c 'unzip -d `dirname {}` {}' ';'

This command looks in current directory and in its subdirectories recursively for files with names matching *.zip pattern. For file found it executes command sh with two parameters:

-c

and

unzip -d `dirname <filename>` <filename>

Where <filename> is name of file that was found. Command sh is Unix shell interpreter. Option -c tells shell that next argument should be interpreted as shell script. So shell interprets the following script:

unzip -d `dirname <filename>` <filename>

Before running unzip shell expands the command, by doing various substitutions. In this particular example it substitutes

`dirname <filename>`

with output of command dirname <filename> which actually outputs directory name where file is placed. So, if file name is ./a/b/c/d.zip, shell will run unzip like this:

unzip -d ./a/b/c ./a/b/c/d.zip

In case you ZIP file names or directory names have spaces, use this:

find . -name '*.zip' -exec sh -c 'unzip -d "`dirname \"{}\"`" "{}"' ';'
Tunnel answered 11/2, 2013 at 13:45 Comment(3)
This looks like a good answer, any chance you could (very quickly) help me understand it? The bit I am confused about it the need for -exec and the {} marks.Varnado
I seem to have a problem if there is a space in the zips file name, is there an easy fix for this?Varnado
@NutterzUK Yes, this is easy to fix. Just need to add quotes. See my last addition to the answer.Tunnel
L
44

Use -execdir instead of -exec, which runs the command in the directory where the file is found, not the directory you run find from.

find . -name '*.zip' -execdir unzip '{}' ';'
Lateral answered 11/2, 2013 at 14:17 Comment(2)
Worked fantastically. Do you mind explaining what the '{}' does (filename placeholder?) and why the ';'` needs to be a separate quote? Thanks!Vizierate
{} means the current file you are operating onSynaesthesia
A
9
find . -name '*.zip' | xargs -n1 unzip
Arianaariane answered 11/2, 2013 at 13:54 Comment(1)
this seems unable to handle options in unzip, e.g., find . -name '*.zip' | xargs -n1 unzip -q ?Gassy
B
0

You probably want the files contained in every foo/bar.zip file to be extracted under a foo/bar/ directory.

find . -name '*.zip' -exec sh -c 'unzip -d "`dirname \"{}\"`"/"`basename \"{}\" .zip`" "{}"' ';'
Bench answered 25/11, 2023 at 6:43 Comment(1)
The quoting here can’t be reliable in general.Voltameter

© 2022 - 2024 — McMap. All rights reserved.