이 질문과 답변에 대해:https://unix.stackexchange.com/a/188020/189709
for f in *; do mv --backup=numbered -- "$f" "${f,,}"; done
rename -v -- 's/\.~(\d+)~/$1/' *.~*~
mv: 이 명령은 모든 파일 이름을 암시적으로 소문자로 변경합니다. 이 작업을 수행하지 않도록 옵션을 어떻게 수정합니까? 백업 번호는 파일을 구별하기에 충분합니다.
이름 바꾸기: test.~1~ test1 파일이 이미 존재하는 경우 이름이 바뀌지 않습니다. test.~1~의 이름을 test2로 바꾸는 옵션을 어떻게 변경합니까?
답변1
mv
보고 있는 코드는 실제 파일 이름 충돌 시 중복 항목을 잡기 위해 호출 시 파일 이름을 명시적으로 소문자로 지정하므로 이름 바꾸기 정책을 직접 구현하는 것이 좋습니다 .
다음은 실제로 충돌을 일으키지 않고 충돌이 있는 경우에만 파일 이름을 바꿉니다(즉, 충돌을 처리하기 위해 GNU로 돌아가지 않습니다 mv
).
#!/bin/bash
# The suffix array contains a filename suffix (a positive integer)
# for each lower-cased filename.
declare -A suffix
# Get all names in the current directory.
set -- *
# Initialise the suffixes for each existing name to zero.
for name do
suffix[${name,,}]=0
done
for name do
# Loop until no name collision.
while true; do
# Get the current suffix for this filename.
suf=${suffix[${name,,}]}
# Increment the suffix for this filename.
suffix[${name,,}]=$(( ${suffix[${name,,}]} + 1 ))
# If the suffix is 0, empty it.
[[ $suf == 0 ]] && suf=
# Create the new name.
newname=$name$suf
# Break out of the loop if the name didn't change, or if
# there's no other file that has this name.
if [[ $name == "$newname" ]] ||
[[ -z ${suffix[${newname,,}]} ]]
then
break
fi
done
if [[ $name != "$newname" ]]; then
printf '%s --> %s\n' "$name" "$newname"
# uncomment the next line to actually do the renaming
# mv -- "$name" "$newname"
else
printf '%s unchanged\n' "$name"
fi
done
(주석 처리된 부분을 참고하세요 mv
. 올바른 작업을 수행한다는 확신이 들 때까지 해당 줄을 주석 처리한 상태로 실행하는 것이 좋습니다.)
시험:
$ ls
A Bb TEST1 a bb test
BB TEST Test bB script.sh
$ bash script.sh
A unchanged
BB unchanged
Bb --> Bb1
TEST unchanged
TEST1 unchanged
Test --> Test2
a --> a1
bB --> bB2
bb --> bb3
script.sh unchanged
test --> test3