mv: add number to file name if the target exists
Solution 1
As the answer to the question you linked already states, mv
can suffix files that would otherwise get overwritten by the file you move with a number to give them a unique file name:
mv --backup=t <source_file> <dest_file>
The command works by appending the next unused number suffix to the file that was first in the destination directory. The file you are moving will keep its original name.
However, this will appends suffixes like .~1~
, which seems to be not what you want:
$ ls
file.pdf
file.pdf.~1~
file.pdf.~2~
You can rename those files in a second step though to get the names in a format like file_1.pdf
instead of file.pdf.~1~
, e.g. like this:
rename 's/((?:\..+)?)\.~(\d+)~$/_$2$1/' *.~*~
This takes all files that end with the unwanted backup suffix (by matching with the shell glob *.~*~
) and lets the rename
tool try to match the regular expression ((?:\..+)?)\.~(\d+)~$
on the file name. If this matches, it will capture the index from the .~1~
-like suffix as second group ($2
) and optionally, if the file name has an extension before that suffix like .pdf
, that will be captured by the first group ($1
). Then it replaces the complete matched file name part with _$2$1
, inserting the captured values instead of the placeholders though.
Basically it will rename e.g. file.pdf.~1~
to file_1.pdf
and something.~42~
to something_42
, but it can not detect whether a file has multiple extensions, so e.g. archive.tar.gz.~5~
would become archive.tar_5.gz
Solution 2
While the simple substitution-based renaming of files in Linux is relatively facile, something to note on Linux distributions is that there are multiple rename
command packages, as noted here:
https://stackoverflow.com/questions/31408764/using-regex-with-rename-version-from-util-linux
Complicating this issue are more complex file renaming approached involving regex (regular expressions) commands.
The rename
solution provided by @ByteCommander did not work for me; here are the specifics and a solution (I'm on Arch Linux).
$ which rename
/usr/bin/rename
$ rename --version
rename from util-linux 2.36.1
$ pacman -Ss util-linux | grep installed
core/util-linux 2.36.1-4 [installed]
core/util-linux-libs 2.36.1-4 [installed]
$ cd /home/victoria/zzz/
$ pwd; ls -l
/home/victoria/zzz
total 16
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 'apples and bananas.mkv'
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 'apples and bananas.mkv.~123~'
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 apples.mkv
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 apples.mkv.~123~
## Note the use of bacticks ( ` ); for readability I split the `for`
## command over two lines; however, it is a one-line command):
$ for f in *; do mv 2>/dev/null -v "$f" "`echo $f |
sed -r 's/(.*)\.(.*)\.~([0-9]{1,})~$/\1_\3.\2/'`"; done
renamed 'apples and bananas.mkv.~123~' -> 'apples and bananas_123.mkv'
renamed 'apples.mkv.~123~' -> 'apples_123.mkv'
$ ls -l
total 16
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 apples_123.mkv
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 'apples and bananas_123.mkv'
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 'apples and bananas.mkv'
-rw-r--r-- 1 victoria victoria 5 Dec 17 09:17 apples.mkv
Comments:
-
Using a
sed
regex command I capture three parts of the source filename, then rearrange them; see (e.g.) https://www.gnu.org/software/sed/manual/html_node/Regular-Expressions.html for explanations of the syntax, and/or web searches for regex capture groups and backreferences, e.g. https://www.regular-expressions.info/refcapture.html -
I get warnings from the command above, which I ignore (redirect/hide) with
2>/dev/null
-
See also re: comments on the
rename
command(s), and the use of thefind
command to rename files.
Related videos on Youtube
Qohelet
Engineer of Information Technology and Accounting Languages: Python Java C/C++ And whatever is needed (JavaScript, PHP, Cobol/CICS, Bash...) Databases, Encryption... Fluent in German, English and Russian. Self-Employed
Updated on September 18, 2022Comments
-
Qohelet over 1 year
I'm moving a file to a different folder and would like to add some kind of index to the newly moved file if a file with the same name exists already (the old one should remain untouched). For example, if
file.pdf
existed I would prefer something likefile1.pdf
orfile_1.pdf
for the next file with the same name.Here I've found a variant for the opposite idea — but I don't want to make a "backup".
Does
mv
have some parameters out of the box for that scenario? I use Ubuntu Linux.-
Admin almost 7 yearsThat is exactly what the solution in your linked question's answer does. Have you tried it?
-
Admin almost 7 yearsDoesn't it actually add the suffix to the original?
-
Admin almost 7 yearsI'd prefer something like
file1.pdf
orfile_1.pdf
-
-
smw almost 7 years"Files that were originally present in the destination folder do not get modified in any way" - sure about that? try
echo 'This is foo' > foo ; echo 'This is bar' > bar ; mv --backup=t foo bar ; cat bar
(it's the originalbar
that becomesbar.~1~
) -
Byte Commander almost 7 years@steeldriver Oops, you're right. That's quite counter-intuitive behaviour in my opinion though. Editing...
-
smw almost 7 yearsYeah I don't know the history of why it was done that way
-
Baard Kopperud almost 7 yearsalso
--backup=numbered
can be used instead of--backup=t