8

I'm looking for a means to extract individual and marked files from archives (e.g., *.zip; *.gz, etc.) to the hard-drive (without opening them in a buffer) using archive-mode. A suggested modification of that major-mode (that would permit this new feature) will be greatly appreciated.

http://www.gnu.org/software/emacs/manual/html_node/emacs/File-Archives.html

1 Answer 1

7

Here's a sketch of an implementation.

Archive mode stores maps from archive types to commands used to extract data in variables archive-TYPE-extract; we can find the right variable using (archive-name "extract").

All commands are tailored for extracting to standard out; luckily we can still use them if we redirect stdout to a file of our choice.

(defun archive-extract-to-file (archive-name item-name command dir) "Extract ITEM-NAME from ARCHIVE-NAME using COMMAND. Save to DIR." (unwind-protect ;; remove the leading / from the file name to force ;; expand-file-name to interpret its path as relative to dir (let* ((file-name (if (string-match "\\`/" item-name) (substring item-name 1) item-name)) (output-file (expand-file-name file-name dir)) (output-dir (file-name-directory output-file))) ;; create the output directory (and its parents) if it does ;; not exist yet (unless (file-directory-p output-dir) (make-directory output-dir t)) ;; execute COMMAND, redirecting output to output-file (apply #'call-process (car command) ;program nil ;infile `(:file ,output-file) ;destination nil ;display (append (cdr command) (list archive-name item-name)))) ;; FIXME: add unwind forms nil)) 

I modified archive-extract-by-file to get this.

(defun archive-extract-marked-to-file (output-dir) "Extract marked archive items to OUTPUT-DIR." (interactive "sOutput directory: ") (let ((command (symbol-value (archive-name "extract"))) (archive (buffer-file-name)) (items (archive-get-marked ?* t))) ; get marked items; t means ; get item under point if ; nothing is marked (mapc (lambda (item) (archive-extract-to-file archive (aref item 0) ; get the name from the descriptor command output-dir)) items))) 

Here I use mapc to loop over all marked files and extract them.

Now we just need to add a key binding:

(require 'arc-mode) (define-key archive-mode-map "F" #'archive-extract-marked-to-file) 

I tested this on a dummy .zip file containing a subdirectory, but your mileage may vary.

Note that archive-mode supports Arc, Lzh, Zip, Zoo, Rar, and 7z. It does not support .tgz, .tbz, .tar.gz and friends, which are opened using tar-mode and uncompress.el.

6
  • @lawlist: Please see the updated answer; now it should be able to extract files contained in subdirectories. Note that it re-creates the directory structure: foo/bar.txt in an archive gets extracted to output-dir/foo/bar.txt, not to output-dir/bar.txt. The latter is possible, of course, but would require some more code. Commented Nov 25, 2014 at 8:10
  • That's really nice. Once you feel confident with it, would you consider adding it to archive-mode itself? Commented Nov 25, 2014 at 10:17
  • @Malabarba: Yes, I would. I'm waiting for a reply from [email protected] (I got this e-mail from Lars Ingebrigtsen) right now; in the meantime I'll clean this up and put it on GitHub. Commented Nov 25, 2014 at 18:53
  • This new feature is awesome! Thank you so very much -- greatly appreciated! This would indeed be a wonderful addition to archive-mode. As you noted, the ability to target a specific output directory without necessarily re-creating the zip-archive directory structure (in the output directory) would be handy. As is, it is certainly worthy of a checkmark+ for the correct answer :) Commented Nov 25, 2014 at 18:57
  • Thanks a lot for this code! One thing though: it'd be better to (interactive "G...") this way it will suggest the current directory, plus it'll autocomplete and interact with Ido mode etc. Commented Mar 10, 2015 at 12:20

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.