Auto increment filename
GNU mv has a --backup
option which may be useful. The following
interaction shows how the files are getting renamed when the target
exists:
$ touch a b c o
$ mv --backup=numbered --verbose a o
`a' -> `o' (backup: `o.~1~')
$ mv --backup=numbered --verbose b o
`b' -> `o' (backup: `o.~2~')
$ mv --backup=numbered --verbose c o
`c' -> `o' (backup: `o.~3~')
In this example, the original file o
has been renamed to o.~1~
,
a
to o.~2~
, b
to o.~3~
, and c
to o
. So this doesn't rename
in the same way that the code you posted does, but this may be
acceptable, depending on your exact needs.
You might do it like:
set -C; num=0 ### set -o noclobber; init $num
[ -e "$1" ] && ### this needs to be true
until 2>&3 >"./DUPES/$((num+=1))-$1" && ### try to open() num+=1
mv -- "$1" "./DUPES/$num-$1" ### if opened, mv over it
do :; done 3>/dev/null ### do nothing
You would at once assure that multiple instances cannot secure the same name for any given file, and increment your variable.
The /dev/null
< stderr just drops the shell's complaint about a file existing when it tries to do the output truncate/redirect and finds an existing target. While noclobber is enabled it won't overwrite another file - it will only open()
a new one unless you use >|
. And so you don't need its complaint because the whole point is to increment over existing files until a non-existing name is found.
Regarding the performance aspect - it would be better if you didn't start at zero. Or, if you tried to make up the difference. I guess the above might be improved somewhat like:
set -C; num=0 ### set -o noclobber; init $num
until 2>&3 >"./DUPES/$((num+=1))-$1" && ### try to open() num+=1
mv -- "$1" "./DUPES/$num-$1" ### if opened, mv over it
do [ -e "./DUPES/$((num*2))-$1" ] && ### halve fail distance
num=$((num*2)) ### up to a point of course
done 3>/dev/null ### done
...but up to 1000 you probably don't have to worry about it terribly. I've got to 65k over random names in a couple seconds.
By the way - you might think you could just:
>"./DUPES/$((num+=1))-$1" mv -- "$1" "./DUPES/$num-$1"
...but it doesn't work in a bash
shell.
num=0; echo >"/tmp/$((num+=1))" >&2 "$num"; echo "$num" /tmp/[01]
0
1 /tmp/1
For whatever reason bash
does the assignment in some other context for redirections - and so the expansions happen in a strange order. So you need a separate simple command to expand the correct $num
value as I get here with &&
. Otherwise, though:
num=0; echo "$((num+=1))" "$num"
1 1