Você pode gostar:
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
Você garantiria de imediato que várias instâncias não podem garantir o mesmo nome para nenhum arquivo e incrementar sua variável.
O /dev/null
< stderr apenas descarta a reclamação do shell sobre um arquivo existente quando ele tenta fazer a saída truncate / redirect e encontra um alvo existente. Enquanto o noclobber estiver ativado, ele não sobrescreverá outro arquivo - somente open()
será novo, a menos que você use >|
. E assim você não precisa de sua reclamação porque o objetivo é incrementar os arquivos existentes até que um nome inexistente seja encontrado.
Em relação ao aspecto do desempenho - seria melhor se você não começasse no zero. Ou, se você tentou compensar a diferença. Eu acho que o acima pode ser melhorado um pouco como:
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
... mas até 1000 você provavelmente não precisa se preocupar com isso terrivelmente. Eu tenho 65k sobre nomes aleatórios em alguns segundos.
A propósito, você pode pensar que poderia:
>"./DUPES/$((num+=1))-$1" mv -- "$1" "./DUPES/$num-$1"
... mas não funciona em bash
shell.
num=0; echo >"/tmp/$((num+=1))" >&2 "$num"; echo "$num" /tmp/[01]
0
1 /tmp/1
Por alguma razão bash
faz a atribuição em algum outro contexto para redirecionamentos - e assim as expansões acontecem em uma ordem estranha. Portanto, você precisa de um comando simples separado para expandir o valor correto de $num
conforme eu chegar aqui com &&
. Caso contrário, porém:
num=0; echo "$((num+=1))" "$num"
1 1