일부 중복 파일을 수집해야 하며 이름 충돌을 피하고 싶습니다. 문제는 파일이 정리되기 전에 내 스크립트를 다시 실행하여 이 파일 모음이 추가될 수 있으며 계속해서 숫자를 늘리려는 것입니다.
나는 아래와 같이 숫자를 증가시키기 위해 간단한 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 및 to o
로 변경되었습니다 . 따라서 게시한 코드와 동일한 방식으로 이름이 바뀌지는 않지만 특정 요구 사항에 따라 허용될 수 있습니다.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
동시에 실행되고 동시에 실행되는 두 개의 제안 인스턴스를 고려해보세요. 그들은 모두 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