5

Let's say I have the following file shown in Windows File Explorer:

enter image description here

If I enter C-c C-v to copy and paste the file, the file is duplicated and automatically given a name:

enter image description here

We can repeat this to get more duplicates which are also automatically named:

enter image description here

Does a similar command exist for dired? I looked for something like dired-do-duplicate but didn't notice anything like that.

Drew
  • 75,699
  • 9
  • 109
  • 225
dharmatech
  • 1,212
  • 7
  • 19
  • 1
    I notice macOS Finder does the similiar, Duplicate menu item uses foo.txt, foo copy.txt, foo copy 2.txt, foo copy 3.txt and so on. – xuchunyang Sep 15 '20 at 10:14

4 Answers4

4

This should do more or less what you request.

(defun dired-duplicate-this-file ()
  "Duplicate file on this line."
  (interactive)
  (let* ((this  (dired-get-filename t))
         (ctr   1)
         (new   (format "%s[%d]" this ctr)))
    (while (file-exists-p new)
      (setq ctr  (1+ ctr)
            new  (format "%s[%d]" this ctr)))
     (dired-copy-file this new nil))
  (revert-buffer))

That copies a file foo to foo[1], or foo[2] if foo[1] exists, etc.

If you want a different naming convention, e.g., foo Copy, foo Copy (2), etc. then use something like this:

(defun dired-duplicate-this-file ()
  "Duplicate file on this line."
  (interactive)
  (let* ((this  (dired-get-filename t))
         (ctr   1)
         (new   (format "%s Copy" this)))
    (while (file-exists-p new)
      (setq ctr  (1+ ctr)
            new  (format "%s Copy (%d)" this ctr)))
     (dired-copy-file this new nil))
  (revert-buffer))

Of course, if you duplicate a file such as foo[2] or foo Copy (2) then you'll get files named like foo[2][1], foo[2][2], ... or foo Copy (2) Copy, foo Copy (2) Copy (2), ...

And if your file has an extension, such as .txt, then the new name will be something like foo.txt[1] or foo.txt Copy. Not sure if that's what you want. If not, you can use functions file-name-sans-extension and file-name-extension to move the extension after the number (if that's what you want), so you get foo[1].txt or foo Copy.txt. It all depends on what you want.

Function format lets you specify the form you want. See C-h f format for info.

Drew
  • 75,699
  • 9
  • 109
  • 225
3

You can do this quite easily, and rather more flexibly, without defining any functions (and probably learning another way of using dired along the way).

  1. Mark the files you want to copy (if no files are marked, operate on the file at point.)
  2. "% C" (dired-do-copy-regexp)
  3. ".*" (copy from regexp) - specify a regexp matching the whole file name
  4. "\&-copy" (copy to) - the input file name, plus "-copy"
  5. You are shown a preview of the copy operation, which you accept with "y" (or "!" if copying multiple files)

A similar approach allows you to rename files ("% R").

mikado
  • 153
  • 8
  • Thanks for the suggestion mikado! This does indeed work, however it's a little bit verbose in terms of keystrokes. This approach seems to take around 16 or so keystrokes. The idea would be to have something like `C-c C-d` call `dired-duplicate-this-file`. – dharmatech Sep 16 '20 at 00:25
2

Based on @mikado's answer I've written a simple function that allows the user to specify the suffix to add to the file being copied, while keeping its extension:

(defun dired-duplicate-this-file (suffix)
  "Duplicate file on this line."
  (interactive (list (read-string "Suffix: " "_COPY")))
  (dired-do-copy-regexp "\\(.*\\)\\.\\(.*\\)"
                        (concat "\\1" suffix ".\\2"))
  )

As any other function, you can invoke it with M-x dired-duplicate-this-file while hovering over a file in a dired buffer, and you can change the default suffix that appears in the mini-buffer.

For instance, a file named "file.txt" will be copied to a new file named "file_COPY.txt".

unvarnished
  • 129
  • 5
0

Here's one approach which is implemented as a keyboard macro

(fset 'macro-dired-do-duplicate
      (lambda (&optional arg)
    "Keyboard macro."
    (interactive "p")
    (kmacro-exec-ring-item
     (quote ([up down 67108896 5 134217847 67 25 32 45 32 67 111 112 121 return 121 101 115 return 103] 0 "%d"))
     arg)))

If I run this macro-dired-do-duplicate on the file abc.txt shown below, we get the following:

enter image description here

Note that this version does not support repeated duplicates. It would be interesting to see a non-macro function implementation of this.

xuchunyang
  • 14,302
  • 1
  • 18
  • 39
dharmatech
  • 1,212
  • 7
  • 19