1
example.zip/
└── example/
    ├── nice.md
    ├── tree.md
    └── diagram.md

Expected:
example.zip/
├── nice.md
├── tree.md
└── diagram.md

example.zip contains a folder with the same name. In it are files that I want to move to the root of the zip file and remove the empty directory.

I looked at the zip man page. Could not find any flags related to the issue or I could be missing something.

I tried the --copy-entries flag. This create a new zip with selected files from the existing zip but also copy over the folder hierarchy.

zip example.zip "*.md" --copy-entries --out example1.zip

I am trying to write a shell script to do this.

Is it possible to do without extracting the zip?

Frank Shrestha
  • 103
  • 1
  • 6
  • Not really. For some zip files it might be possible if you don't mind using a hex editor. Requires a good understanding of the structure of a zip file and a lot of patience. Only practical approach is to unzip, rename and zip. – pmqs Sep 15 '22 at 11:31

2 Answers2

3

If you have (or can install) 7z (aka p7zip) you can make use of the d(delete) and rn(rename) options, eg:

$ mkdir example
$ touch example/{nice.md,tree.md,diagram.md}

$ zip -r example.zip example
  adding: example/ (stored 0%)
  adding: example/diagram.md (stored 0%)
  adding: example/nice.md (stored 0%)
  adding: example/tree.md (stored 0%)

$ unzip -l example.zip
Archive:  example.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  09-15-2022 09:29   example/
        0  09-15-2022 09:29   example/diagram.md
        0  09-15-2022 09:29   example/nice.md
        0  09-15-2022 09:29   example/tree.md
---------                     -------
        0                     4 files

# rename the *.md files first and then delete the directory; if you delete
# the directory first you'll lose all files under the directory; the 7z d/rn 
# commands will generate a lot of output (not shown here)

$ 7z rn example.zip example/nice.md    nice.md
$ 7z rn example.zip example/tree.md    tree.md
$ 7z rn example.zip example/diagram.md diagram.md
$ 7z  d example.zip example

$ unzip -l example.zip
Archive:  example.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  09-15-2022 09:29   diagram.md
        0  09-15-2022 09:29   nice.md
        0  09-15-2022 09:29   tree.md
---------                     -------
        0                     3 files

$ unzip example.zip
Archive:  example.zip
 extracting: diagram.md
 extracting: nice.md
 extracting: tree.md

I'm guessing in OP's real life example the names of the directories and/or files may not be known in advance; the 7z commands do work with bash variables (eg, 7z d "${zipfile}" "${dir_to_delete}"); if OP has issues dynamically processing the contents of a given *zip then I'd recommend asking a new question ...


For a large number of renames (or deletes) it looks like you can also:

markp-fuso
  • 28,790
  • 4
  • 16
  • 36
  • Did not work for me unfortunately. – Frank Shrestha Sep 16 '22 at 10:03
  • The command worked but the zip file did not change. – Frank Shrestha Sep 16 '22 at 10:13
  • @FrankShrestha can you update the question to show a) the unzip -l output from before the operation, b) the 7z commands you ran and c) the unzip -l output after the operation? also the version (see first line of output from 7z --help), in my case I'm running 15.14; I just ran all the code again (with empty and non-empty files) and everything works as shown in the answer ... – markp-fuso Sep 16 '22 at 15:23
-1

Good answer. Just to be clear, 7z does not do an in-place edit on the zip file when it does the rename/delete. Under the hood it copies the old zip into a temporary file (example.zip.tmp in this instance), renaming & deleting as it does that copy. Then it deletes the original zip file and renames the temporary file, example.zip.tmp back to original filename, example.zip. For the most part this is a perfectly acceptable (and safe) approach.

Here are the relevant lines from an strace run that shows the deletion of th eoriginal example.zip file, followed by renaming the example.zip.tmp file to example.zip.

$ strace 7z rn example.zip example/tree.md    tree.md 
...
unlink("example.zip")                   = 0
rename("example.zip.tmp", "example.zip") = 0
...

Main edge condition of this approach is with very large zip files where you are strapped for disk space -- you need to have space available to store the zip file twice when it creates the temporary copy.

pmqs
  • 3,066
  • 2
  • 13
  • 22