26

I would like to run unzip (or even zip) within dired or a dired-like buffer. Is there anything like this? I would like something similar as in the Nautilus file manager: i.e., selecting files and then pressing a keystroke to get these files into a new archive file.

Thank you

Damien Cassou
  • 2,555
  • 1
  • 16
  • 21

2 Answers2

36

You've got options...

To uncompress a .zip file, you just need to add to the variable 'dired-compress-file-suffixes

(eval-after-load "dired-aux"
   '(add-to-list 'dired-compress-file-suffixes 
                 '("\\.zip\\'" ".zip" "unzip")))

Now the Z key in dired will recognize the .zip extension and uncompress a .zip archive. Already supported are gunzip, bunzip2, uncompress and dictunzip.

If you want to mark files and add them to a .zip archive you can use the following to make z bound to zip the set of marked files:

(eval-after-load "dired"
  '(define-key dired-mode-map "z" 'dired-zip-files))
(defun dired-zip-files (zip-file)
  "Create an archive containing the marked files."
  (interactive "sEnter name of zip file: ")

  ;; create the zip file
  (let ((zip-file (if (string-match ".zip$" zip-file) zip-file (concat zip-file ".zip"))))
    (shell-command 
     (concat "zip " 
             zip-file
             " "
             (concat-string-list 
              (mapcar
               '(lambda (filename)
                  (file-name-nondirectory filename))
               (dired-get-marked-files))))))

  (revert-buffer)

  ;; remove the mark on all the files  "*" to " "
  ;; (dired-change-marks 42 ?\040)
  ;; mark zip file
  ;; (dired-mark-files-regexp (filename-to-regexp zip-file))
  )

(defun concat-string-list (list) 
   "Return a string which is a concatenation of all elements of the list separated by spaces" 
    (mapconcat '(lambda (obj) (format "%s" obj)) list " ")) 
Trey Jackson
  • 73,529
  • 11
  • 197
  • 229
  • doesn't 'Z' do it out-of-the-box? (or mark it with 'm' and then hit 'Z'). I recall it worked for me a while back. I saw it here: http://xahlee.org/emacs/file_management.html – hatmatrix Sep 17 '09 at 05:02
  • 1
    `Z` will compress the files, each of them individually. It doesn't add them to an archive/zip. – Trey Jackson Sep 17 '09 at 05:48
  • It seems concat-string-list does not exist: concat: Symbol's function definition is void: concat-string-list – Damien Cassou Sep 18 '09 at 11:05
  • Ok, I've implemented it: (defun concat-string-list (list) "Return a string which is a concatenation of all elements of the list separated by spaces" (mapconcat '(lambda (obj) (format "%s" obj)) list " ")) – Damien Cassou Sep 18 '09 at 12:58
  • 1
    Sorry about that, I forgot I had that in my own helper functions, I'll add it to the answer code. – Trey Jackson Sep 18 '09 at 14:11
  • it also seems that 'dired-compress-file-suffixes is defined by dired-aux and not by dired itself. Which makes the eval-after-load not working. I changed "dired" by "dired-aux" and it now works ok. – Damien Cassou Sep 20 '09 at 13:33
  • 1
    I think the above code needs some escaping for filenames, try marking a few files like `2010_12_HEAD_Seminar (1).pdf` and see what happens. – monotux May 05 '11 at 07:13
  • In Emacs 25, you can use `string-join` from `subr-x` instead of `concat-string-list`. – Resigned June 2023 Mar 14 '17 at 16:57
  • I am experiencing the same as @monotux. Is there a way to compress files that have spaces in between names? Annoyingly several people tend to use spaces instead of underscores or dashes. Thank you in advance. – Ajned Aug 27 '20 at 06:06
24

To zip files, open the directory in dired. Mark the files you want to zip with m. Then type

! zip foo.zip * <RET>

To extract an entire archive from dired you can mark a file and run & unzip, just as you would in a shell.

zip-archive mode will allow you to browse zip files in a dired-like fashion. It should come with recent versions of GNU emacs and will be used by default when you visit a file with the .zip extension. From this mode you can extract individual files into a buffer, and from there save them with C-x C-s.

p00ya
  • 3,659
  • 19
  • 17