119

I have a zip archive (created automatically in a script with -j -r flags) and I would like to remove a single file from it. I tried as documented.

zip -d "picture_43_9.jpg" gallery.zip

but I get this error:

zip warning: picture_43_9.jpg not found or empty   
zip error: Nothing to do! (picture_43_9.jpg)  

Anyway, there is such a file inside the archive and it is not empty:

unzip -l .../gallery.zip | grep -i 43_9.jpg  
1477092  2013-05-22 14:23   picture_43_9.jpg 

Any ideas on what I'm doing wrong?

1 Answer 1

180

You have the arguments swapped. Try this:

zip -d gallery.zip "picture_43_9.jpg" 

From the zip(1) man page:

-d
--delete
Remove (delete) entries from a zip archive. For example:

zip  -d  foo  foo/tom/junk  foo/harry/\*  \*.o

will remove the entry foo/tom/junk, all of the files that start with foo/harry/, and all of the files that end with .o (in any path). Note that shell pathname expansion has been inhibited with backslashes, so that zip can see the asterisks, enabling zip to match on the contents of the zip archive instead of the contents of the current directory. (The backslashes are not used on MSDOS-based platforms.) Can also use quotes to escape the asterisks as in

zip -d foo foo/tom/junk "foo/harry/*" "*.o"

Not escaping the asterisks on a system where the shell expands wildcards could result in the asterisks being converted to a list of files in the current directory and that list used to delete entries from the archive.

Under MSDOS, -d is case sensitive when it matches names in the zip archive. This requires that file names be entered in upper case if they were zipped by PKZIP on an MSDOS system. (We considered making this case insensitive on systems where paths were case insensitive, but it is possible the archive came from a system where case does matter and the archive could include both Bar and bar as separate files in the archive.) But see the new option -ic to ignore case in the archive.

5
  • 1
    You're right, thanks, I got confused by the command line help of zip zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]
    – Alex Flo
    Commented May 27, 2013 at 8:23
  • 1
    @AlexFlo: You may have a bad copy of the man page. The copy cited above says “[zipfile [file …]]”, which means you can have (a) no filename arguments at all (although I don’t know how that can be valid, other than when you’re asking for help), (b) a zipfile (archive file) name only, or (c) a zipfile name followed by one or more ordinary file names. (These can be the names of actual files to be inserted into the archive, or names of archive members to be manipulated.) Commented Dec 2, 2013 at 21:15
  • 1
    @AlexFlo - You can pass filename arguments via STDIN and pipe to zip, as stated in the man page that you cited. For instance, if you're in a directory containing file1.txt, file2.txt, and file3.txt, you can execute ls -1 | zip -q 'files.zip' -@, which will create the archive files.zip containing the 3 files you piped to zip with their filenames intact. Commented Oct 23, 2015 at 2:15
  • How much resources does take an action like this? Will the whole zip file extracted in the background, one file removed and then compressed/packaged again?
    – buhtz
    Commented Dec 15, 2022 at 12:17
  • @buhtz This operation takes almost no resources, and is time constant (in complexity). Since each file is compressed in Deflate separately, there is no need to extract and recompress other (untouched) files. Commented Nov 4, 2023 at 17:13

You must log in to answer this question.

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