Create copies of files in same directory

12,058

Solution 1

In plain Unix style you’d need to loop over the files:

for file in 1.txt 2.txt 3.txt; do cp -pi "$file" "${file%.*}(1).txt"; done

${file%.*} removes the extension from the filename, then (1).txt adds the number and restores the extension. The options to cp prompt if a target already exists (-i) and preserve permissions (-p).

Most Linux systems will have the mmv package available; that allows you to simply do

mcp '*.txt' '#1(1).txt'

This copies every file ending in .txt to a new file, matching the first wildcard (#1) and appending (1).txt. The parentheses don’t need escaping here because they’re within quotes.

Alternatively, if you use a graphical file manager, you can do exactly the same as you would in Windows.

Solution 2

In zsh, wildcard move or copy is shipped with the shell:

autoload zmv
zmv -C '(*).txt' '$1 (1).txt'

But I would really advise against using a space in a filename for this purpose, and parentheses are also not ideal. I mention this because every time I encounter a pattern like this (for instance x.txt and x (1).txt and x (2).txt) and want to do tab completion without double quotes, I have to write x <tab> <backslash> <space> <backslash> ( 1 <tab> to get it right. Also, it looks confusing in ls output because it's not really clear where the filenames end. I'd use x.txt, x.1.txt and x.2.txt. This way, the filenames visually apear as single units, and this completion works: x <tab> .1 <tab>.

Solution 3

set ./*.txt
while    [ -e "$1" ] || [ -L "$1" ]
do       case ${1##*(} in ($1|*[!0-9]*\)|\)*)
         cp "$1" "${1%.*}(1).txt";;
         (*\)*) set "${1##*(}" "$@"; cp \
         "$2" "${2%"$1"}$((${1%)*}+1))).txt"
         shift;; esac
shift;   done

That should handle all cases pretty well, I think. It will increment the (copy) number if necessary - but will otherwise just insert a (1) between the extension and the file name.

Solution 4

This seems trivial on Windows, just highlight a bunch of files

I thing it is trivial in various GUI file managers in Linux too, but you need shell solution, right? Here it is:

for F in *; do cp -p "$F" "${F%.*}\(1\).${F#*.}"; done

${F%.*} extracts part of filename before dot, while ${F#*.} extracts extension.

Share:
12,058

Related videos on Youtube

bk201
Author by

bk201

Updated on September 18, 2022

Comments

  • bk201
    bk201 almost 2 years

    Lets say I have a directory with the following files:

    1.txt 2.txt 3.txt
    

    I want to copy these and basically paste in the same directory making new files eg:

    1.txt 1(1).txt 2.txt 2(1).txt 3.txt 3(1).txt
    

    This is harder than I thought! This seems trivial on Windows, just highlight a bunch of files, copy/paste, and it creates the same files but adds 'Copy' into the name.

    • muru
      muru over 9 years
      The Windows trick also works on some file browsers like Nautilus and Nemo.
  • Hauke Laging
    Hauke Laging over 9 years
    ${F#*.} will fail if there is more than one dot in the file name.
  • Hauke Laging
    Hauke Laging over 9 years
    It would make sense to check first whether the target file name already exists (e.g. if the code is run twice accidentally).