Create copies of files in same directory
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.
Related videos on Youtube
bk201
Updated on September 18, 2022Comments
-
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 over 9 yearsThe Windows trick also works on some file browsers like Nautilus and Nemo.
-
-
Hauke Laging over 9 years
${F#*.}
will fail if there is more than one dot in the file name. -
Hauke Laging over 9 yearsIt would make sense to check first whether the target file name already exists (e.g. if the code is run twice accidentally).