いくつかの重複ファイルを収集する必要があり、名前の競合を避けたいです。問題は、ファイルがクリーンアップされる前にスクリプトを再実行してこのファイルのコレクションを追加することができ、引き続き数字を増やすことです。
私は以下のように数字を増やすために単純なUntilループを使用することにしました。
until [[ ! -f ${PWD}/DUPES/${num}-$1 ]]; do
num=$((num +1))
done
mv --no-clobber $1 ${PWD}/DUPES/${num}-$1
極端な場合、ファイルが1kを超えるとは想像できません。だから私の質問は...
これはこれを達成するための非常に非効率的な方法ですか?そこから増加する最も高い先行数を得るために既存のファイルを解析する必要がありますか、それとも私が提示した極端な例には問題ありませんか?それとももっと良い方法がありますか?
答え1
GNU mvには--backup
便利なオプションがあります。次の対話は、ターゲットが存在するときにファイル名を変更する方法を示しています。
$ 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~')
この例では、元のファイルの名前が、to、to、およびtoo
に変更されました。したがって、公開したコードと同じ方法で名前を変更することはありませんが、特定の要件に応じて許可される可能性があります。o.~1~
a
o.~2~
b
o.~3~
c
o
答え2
次のことができます。
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
複数のインスタンスは、特定のファイルの名前が同じであることを確認し、変数を増やすことができないことをすぐに確認します。
< /dev/null
stderrは出力の切り捨て/リダイレクトを実行し、既存のターゲットを見つけようとすると、ファイルの存在に関するシェルの苦情を排除します。しかし、ノクロボ有効にすると、他のファイルは上書きされません。をopen()
使用しない限り、新しいファイルのみが上書きされます>|
。したがって、存在しない名前が見つかるまで既存のファイルを増やすので、文句を言う必要はありません。
パフォーマンスについて - それ会議最初から始めないことをお勧めします。または違いを埋めようとする場合。上記の内容が改善されると思います。たとえば、次のようになります。
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
...しかし、1000個以内ではあまり心配する必要はありません。数秒で65,000を超えるランダムな名前を得ました。
ところで - あなたは次のことができると思うかもしれません:
>"./DUPES/$((num+=1))-$1" mv -- "$1" "./DUPES/$num-$1"
...しかし、シェルでは動作しませんbash
。
num=0; echo >"/tmp/$((num+=1))" >&2 "$num"; echo "$num" /tmp/[01]
0
1 /tmp/1
何らかの理由で、bash
リダイレクトの割り当ては別のコンテキストで発生するため、拡張は奇妙な順序で行われます。したがって、正しい$num
値を拡張するには別の単純なコマンドが必要です&&
。それ以外の場合は、次のようになります。
num=0; echo "$((num+=1))" "$num"
1 1
答え3
同時に実行され、同時に実行される2つの提案インスタンスを考えてみましょう。彼らはすべてnum = 4が利用可能であることを発見し、すべて同じターゲット名を使用しようとします。
今はこの選択肢をテストできませんが、このようなもので十分です。
num=1 attempt=10
while ! mv --no-clobber "$1" "${PWD}/DUPES/${num}-$1" && [[ 0 -lt $attempt ]]
do
num=$((num+1))
attempt=$((attempt-1))
done
[[ 0 -eq $attempt ]] && echo "ERROR: Too many attempts to handle $1" >&2