17

Is there a simple M-w C-y approach to copy paste files and directories between two dired buffers?

I mean marking some items (files and buffer) by m then copying them by M-w (or another shortcut), then going to another dired buffer (which is not necessarily in a window side-by-side by the window of previous dired buffer(s)) then yanking all copied file by C-y (or another shortcut) there? This is a simple task that many file explorers in different OS can do.

The problem with the classical Copy option C in dired is that as soon as it is pressed, it asks for the destination. If the path of the destination buffer is very long or there are too many opened dired buffer, this approach is complicated.

I am looking for a solution to first copy the items then to paste them at an appropriate dired buffer.

There is a related question How to quickly copy/move file in Emacs Dired? which uses the classical approach of pressing C when two dired windows separated vertically using the option (setq dired-dwim-target t).

What are the ways to achieve this?

Name
  • 7,689
  • 4
  • 38
  • 84

7 Answers7

14

You can do the following in vanilla Dired (no 3rd-party library needed):

  1. Go first to a Dired buffer that lists the target directory.

  2. With the cursor on the directory header line for a listing of the target directory, use w (command dired-copy-filename-as-kill). This copies the absolute name of that target directory. (You can copy a dir name from any Dired-listing subdir header line in the same way.)

  3. Go to the Dired buffer that lists the files you want to copy. Mark those files.

  4. Use C (command dired-do-copy) to copy the marked files. At the prompt, use C-y to paste the (absolute) name of the target directory. You can just paste it, without bothering to remove the default directory that is inserted in the minibuffer. (Pasting it after that default dir name dims that default name - it is ignored.)

This is, I think, as simple as what you describe (C-w to copy marked file names followed by C-y in the target Dired listing), but the order is opposite: you copy the target directory name first, and then paste it to the C (dired-do-copy) command.

(dired-do-copy checks for existing files of the same name in the target dir, etc.)


Tip: (This is not needed if you use Dired+ - see my other answer here.) If you intend to copy (or move) files from multiple directories to the same target directory, and you might be doing other things with the kill-ring in between, so that the copied target dir name might no longer be first in the kill-ring, then use the secondary selection to select the target dir name. The secondary selection doesn't depend on the region or the position of the cursor - you can paste it as many times as you want, regardless of changes to the kill-ring. You can paste it using the mouse, but it is handier to use C-M-y from library second-sel.el.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • 1
    Thanks, this helped a lot! I struggled with simply moving some files into a newly created subdirectory because the default was the directory on the other side of the split - which is normally nice, but wasn't in this case. – xeruf Apr 21 '21 at 09:10
8

I've added this feature now to Dired+.

You can use C-y (command diredp-yank-files) to paste files, whose absolute names you have copied to the kill ring, to the current directory. The "current directory" here is what dired-current-directory returns: the inserted subdirectory where the cursor is located, or the Dired main directory if the cursor is not in a subdir listing.

With a prefix arg, C-y instead prompts you for the target directory for the paste. So you do not need to be in a Dired buffer to paste files to a directory.

You should have copied file names to the kill ring using M-0 w or M-x diredp-copy-abs-filenames-as-kill.

In Dired+ those commands also set variable diredp-last-copied-filenames to the same string of file names. C-y uses the value of that variable, not whatever is currently at the head of the kill ring. This means that you need not paste immediately after you copy file names. And it means that you could, instead of copying file names to the kill ring, just put the names in that variable (e.g. programmatically).

When you use C-y, you are prompted for confirmation (y or n). You can also hit l (for "list") when prompted, to display the list of files that will be pasted.


You can also copy the marked files from the current Dired buffer and any marked files in its marked subdirectories, defined recursively. For that you use M-0 M-+ M-w (zero prefix arg with command diredp-copy-filename-as-kill-recursive) or use M-x diredp-copy-abs-filenames-as-kill-recursive.


Note that with Dired+ you can also easily have a Dired buffer that lists any number of files and directories, from anywhere. That is, the entries listed need not be in the same directory or even in related directories. See C-x D F (command diredp-dired-for-files), which is on the Dir menu-bar menu as item Dired Files Located Anywhere. You can mark and then paste (copy) such arbitrary files from a Dired buffer to any directory.


Update 2019-04-22:

I also added the ability to move (not just paste) the files whose (absolute) names you copied to the kill ring to the current (or another) directory. This is bound to C-w in Dired.

diredp-move-files-named-in-kill-ring is an interactive Lisp function in dired+.el.

(diredp-move-files-named-in-kill-ring &optional DIR NO-CONFIRM-P DETAILS)

Move files, whose absolute names you copied, to the current directory.

With a non-negative prefix arg you are instead prompted for the target directory.

With a non-positive prefix arg you can see details about the files if you hit l when prompted to confirm pasting. Otherwise you see only the file names. The details you see are defined by option diredp-list-file-attributes.

You should have copied the list of file names as a string to the kill ring using M-0 w or M-x diredp-copy-abs-filenames-as-kill. Those commands also set variable diredp-last-copied-filenames to the same string. diredp-move-files-named-in-kill-ring uses the value of that variable, not whatever is currently at the head of the kill ring.

When called from Lisp:

  • Optional arg NO-CONFIRM-P means do not ask for confirmation to move.
  • Optional arg DETAILS is passed to diredp-y-or-n-files-p.
Drew
  • 75,699
  • 9
  • 109
  • 225
  • Worked nice. Do diredp had `C-w` to move/rename file instead of copy ?. Thanks – azzamsa Oct 08 '18 at 08:40
  • @azzamsa: No, I don't think so. (I guess you mean use file names that are on the `kill-ring` to tell Dired to move those files somewhere, e.g., prompting for where to move them.) – Drew Oct 08 '18 at 13:35
  • Sure. I mean why don't you add this functionality ? it would be awesome :). Because the current, only support C-y. Copy only, Not move/rename. – azzamsa Oct 08 '18 at 15:17
  • Now. I use [dired-ranger hack](https://github.com/Fuco1/dired-hacks#dired-ranger) for [this](http://pragmaticemacs.com/emacs/copy-and-paste-files-with-dired-ranger/) Thanks. – azzamsa Oct 10 '18 at 20:08
  • FYI - You can now use `C-w` to move the files whose names you copied. – Drew Apr 22 '19 at 12:02
  • `diredp-copy-abs-filenames-as-kill-recursive` copied the files with space as the separator, and `diredp-yank-files` can't handle that. Is this a regression? – HappyFace May 10 '21 at 00:46
  • 1
    @HappyFace: Good catch; thx. Forgot to update the recursive command when I added option `diredp-filename-separator`. Should be fixed now. Please download the latest [`dired+.el`](https://www.emacswiki.org/emacs/download/dired%2b.el). – Drew May 10 '21 at 16:16
  • I noticed that it fails when there's white space in the path of the files (either in the file name or the directory name.) Could you confirm this? If so, is there a quick fix for it? – Boson Bear Nov 07 '21 at 09:36
  • @HappyFace: Thanks for the report. I don't have the time to look into it right now. Please use `M-x diredp-send-bug-report` to report this by mail, and I'll take a look when I get a moment. Thx. – Drew Nov 08 '21 at 00:23
  • @BosonBear: Sorry, my previous comment here was intended for you, not user HappyFace (I wrote the wrong name). Please send a clear report of what you tried and what you feel is incorrect. I don't know whether you're talking about the recursive version of the command or what. A recipe will help. Thx. – Drew Nov 09 '21 at 01:38
  • @BosonBear: Ping. Do you still see a problem? If so, could you please report it, preferably with a recipe to reproduce it. Use `M-x diredp-send-bug-report` to report by email. (Or you can post it here as a question.). Thx. – Drew Dec 11 '21 at 17:32
  • @Drew Sorry for taking so long to get back -- I just submitted a bug report using `diredp-send-bug-report`. Thanks – Boson Bear Mar 14 '22 at 19:09
  • @BosonBear: Thanks for following up by email. I think maybe I fixed that bug a year ago. Please try the latest version of [`dired+.el`](https://www.emacswiki.org/emacs/download/dired%2b.el). – Drew Mar 14 '22 at 21:05
4

Your idea sounds straightforward, maybe you can try to implement it by yourself, you can also use the following to get started if you want to.

(defvar your-dired-copy-list nil)

(defun your-dired-copy ()
  (interactive)
  (setq your-dired-copy-list (dired-get-marked-files)))

(defun your-dired-paste ()
  (interactive)
  (when your-dired-copy-list
    (shell-command
     (mapconcat
      #'shell-quote-argument
      `("cp" "-r" ,@your-dired-copy-list ,default-directory)
      " "))
    (setq your-dired-copy-list nil)))
xuchunyang
  • 14,302
  • 1
  • 18
  • 39
  • Thank you very much. I have a suggestion: after pasting , update (refresh) the dired buffer in order to see the new copied items. – Name Feb 27 '18 at 11:45
  • Another suggestion: to unmark the marked items after pasting. – Name Feb 27 '18 at 11:48
  • @Name Good suggestions. I recommend you implement them by yourself since you are the one who is going to use it. Good luck. – xuchunyang Feb 27 '18 at 12:59
2

Ranger file manager works the way you describe, but it is inspired by vim (thus vim keybindings yy to yank/copy p to paste etc). Emacs also has implementation of ranger. Try it, maybe it'll fit your need.

I for myself use emacs sunrise-commander which kind of similar to Midnight Commander (mc), whenever I feel I need double-panes-files-managing.

Upd: dired-ranger has that copy/paste you have described. At least in the docs.

;; Multi-stage copy/pasting of files
;; ---------------------------------

;; A feature present in most orthodox file managers is a "two-stage"
;; copy/paste process.  Roughly, the user first selects some files,
;; "copies" them into a clipboard and then pastes them to the target
;; location.  This workflow is missing in dired.

;; In dired, user first marks the files, then issues the
;; `dired-do-copy' command which prompts for the destination.  The
;; files are then copied there.  The `dired-dwim-target' option makes
;; this a bit friendlier---if two dired windows are opened, the other
;; one is automatically the default target.

;; With the multi-stage operations, you can gather files from
;; *multiple* dired buffers into a single "clipboard", then copy or
;; move all of them to the target location.  Another huge advantage is
;; that if the target dired buffer is already opened, switching to it
;; via ido or ibuffer is often faster than selecting the path.

;; Call `dired-ranger-copy' to add marked files (or the file under
;; point if no files are marked) to the "clipboard".  With non-nil
;; prefix argument, add the marked files to the current clipboard.

;; Past clipboards are stored in `dired-ranger-copy-ring' so you can
;; repeat the past pastes.
;; ...
Maxim Kim
  • 1,516
  • 9
  • 17
1

I also would suggest to use dired-ranger. This is what I have in my init.el:

(use-package dired-ranger
  :ensure t
  :config
  (setq dired-ranger-copy-ring-size 1)
    (define-key dired-mode-map (kbd "C-w")
        (lambda ()
            (interactive)
            (dired-ranger-copy nil) ; t adds item to dired-ranger-copy-ring
            (define-key dired-mode-map (kbd "C-y") 'dired-ranger-move)))
    (define-key dired-mode-map (kbd "M-w")
        (lambda ()
            (interactive)
            (dired-ranger-copy nil)
            (define-key dired-mode-map (kbd "C-y") 'dired-ranger-paste)))
)
Timm
  • 1,549
  • 12
  • 23
1

[The OP posted an answer to his own question but then deleted it - I don't understand why, since it was a perfectly good answer to the question in the title, even though it does not implement what he asked in the body of the question. So for the benefit of future visitors to this question, I will provide his answer - if he decides to undelete his answer in the future, I will delete mine.]

The most convenient way I know to copy (or move) files/directories from one directory to another, is to customize the option dired-dwim-target to t and then open both the source and destination directories in dired: that is much easier than typing a long pathname since you can use completion on paths. Mark the files you want to copy (or move) and then execute the action: C for copy, R for rename. dwim stands for do what I mean and the fact that you have the destination open in dired shows that you mean to copy/move the files to that directory.

One caveat is that if there is a third directory open in dired and shown in a window, dired might mistakenly pick that as the destination directory. But all you have to do is hide it (C-x 0 in the errant directory's window) to tell dired exactly what you mean.

NickD
  • 27,023
  • 3
  • 23
  • 42
0

Dired ranger was the true solution for me:

You can achieve common file explorer behavior as you describe, just with this simple config (assuming you use use-package):

(use-package dired-ranger
  :bind (:map dired-mode-map
              ("W" . dired-ranger-copy)
              ("X" . dired-ranger-move)
              ("Y" . dired-ranger-paste)))
azzamsa
  • 634
  • 7
  • 16