12

I've so far figured out how to use find to recursively unzip all the files:

find . -depth -name `*.zip` -exec /usr/bin/unzip -n {} \; 

But, I can't figure out how to remove the zip files one at a time after the extraction. Adding rm *.zip in an -a -exec ends up deleting most of the zip files in each directory before they are extracted. Piping through a script containing the rm command (with -i enabled for testing) causes find to not find any *.zips (or at least that's what it complains). There is, of course, whitespace in many of the filenames but at this point syntaxing in a sed command to add _'s is a bit beyond me. Thank for your help!

apaderno
  • 28,547
  • 16
  • 75
  • 90
Ben
  • 123
  • 1
  • 1
  • 4
  • What do you mean `recursively`, zip in zip? For complex tasks, personally I'd write a helper script (say `unzip-and-rm.sh`) and -exec that script. – Lenik Apr 08 '11 at 04:26
  • I apologize if I wasn't clear enough. The directory tree goes at least six or seven levels down with the zip files being at the deepest levels. Each zip file contains two other files, and I wish to keep the other files untouched but then remove the zip file. My original try here was just to plug the `unzip-and-rm` into a script and -exec it, but it fails to find any zip files, and I suspect it's due to to the spaces in the filenames. – Ben Apr 08 '11 at 04:33
  • I don't know why `it fails to find any zip files`, I can't believe it, could you paste the command line? – Lenik Apr 08 '11 at 04:47
  • Please, take a look at the answer at https://stackoverflow.com/a/51841035/2457251 if you want more insights. For example, you can add the command `rm $f`, `mv $f` to the .sh file - or add any other command, if you like. – Almir Campos Aug 14 '18 at 12:17

5 Answers5

15

have you tried:

find . -depth -name '*.zip' -exec /usr/bin/unzip -n {} \; -exec rm {} \;

or

find . -depth -name '*.zip' -exec /usr/bin/unzip -n {} \; -delete

or running a second find after the unzip one

find . -depth -name '*.zip' -exec rm {} \;   
cmcginty
  • 113,384
  • 42
  • 163
  • 163
ggiroux
  • 6,544
  • 1
  • 22
  • 23
  • I get a `find: paths must precede expression: /usr/bin/unzip`. – Ben Apr 08 '11 at 04:45
  • Ah! The second option works perfectly. `-delete`, how I never knew ye! One of the main criteria that of course I forgot to mention is that the unzipping and deleting should happen back to back, as the drive is not large enough to unzip everything and then go back to delete. Thank you so much! – Ben Apr 08 '11 at 04:51
  • Warning: the third option does NOT work when in the zip files are other zip files. – flolo Apr 08 '11 at 05:03
  • 2
    -1 warning this command will extract all zips into your working dir. It would be better if the zips were left in the path they were found in. – cmcginty May 20 '15 at 01:38
  • Note that if you have more than one `(i)name` clause, these must be enclosed in parentheses: `find \( -iname "*.zip" -o -iname "*.7z" \) -execdir 7z x {} \; -delete` – Luca Citi Jan 17 '19 at 20:21
10

thx for the 2nd command with -delete! helped me a lot.. just 2 (maybe helpful) remarks from my side:

-had to use '.zip' instead of `.zip` on my debian system

-use -execdir instead of -exec > this will extract each zip file within its current folder, otherwise you end up with all extracted content in the dir you invoked the find cmd.

find . -depth -name '*.zip' -execdir /usr/bin/unzip -n {} \; -delete

THX & Regards, Nord

Nordmann
  • 101
  • 1
  • 2
  • You could add an additional remark that if you have more than one `(i)name` clause, these must be enclosed in parentheses: `find \( -iname "*.zip" -o -iname "*.7z" \) -execdir 7z x {} \; -delete`. Also note that `iname` may be better as it also matches `.ZIP`. – Luca Citi Jan 18 '19 at 09:47
5

As mentioned above, this should work.

find . -depth -name '*.zip' -execdir unzip -n {} \; -delete

However, note two things:

  • The -n option instructs unzip to not overwrite existing files. You may not know if the zip files differ from the similarly named target files. Even so, the -delete will remove the zip file.
  • If unzip can't unzip the file--say because of an error--it might still delete it. The command will certainly remove it if -exec rm {} \; is used in place of -delete.

A safer solution might be to move the files following the unzip to a separate directory that you can trash when you're sure you have extracted all the files successfully.

John D.
  • 1,569
  • 2
  • 13
  • 11
2

Unzip archives in subdir based on the file name (../file.zip -> ../file/..):

for F in $(find . -depth -name *.zip); do unzip "$F" -d "${F%.*}/" && rm "$F"; done
cmcginty
  • 113,384
  • 42
  • 163
  • 163
0

I have a directory filling up with zipped csv files. External processes are writing new zipped files to it often. I wish to bulk unzip and remove the originals as you do.

To do that I use:

    unzip '*.zip'
    find . | sed 's/$/\.zip/g' | xargs -n 1 rm 

It works by searching and expanding all zip files presently in the directory. Later, after it finishes there are potentially new unzipped new files mixed in there too that are not to be deleted yet.

So I delete by finding successfully unzipped *.csv files, and using sed to regenerate the original filenames for deletion which is then fed to rm via the xargs command.

Minkymorgan
  • 479
  • 4
  • 9