나는 사용하고있다사례.
다음 명령이 유효합니다.
$ mv camelCase (ccase -t Kebab camelCase)
이제 다음을 사용하여 여러 디렉터리의 이름을 바꾸려고 합니다.
$ find . -type d -execdir rename 's/(.*)/$(ccase -t Kebab $1)/' '{}' \+
작동하지 않습니다. 다음 오류 메시지가 나타납니다.
Can't rename ./camelCase3 1000 4 24 27 30 46 121 132 1000ccase -t Kebab ./camelCase3): No such file or directory
어떡해?
답변1
해야 한다:
find . -depth ! -name . -type d -execdir sh -c '
for dir do
dir=${dir#*/} # remove the ./ prefix that some find implementations add
new_dir=$(ccase -t Kebab -- "$dir") || continue
[ "$dir" = "$new_dir" ] ||
mv -i -- "$dir" "$new_dir"
done' sh {} +
안 돼요그것들을 {}
에 포함시키세요암호sh
/ 또는 언어 해석기에 대한 인수 bash
로 인해 명령 주입 취약점이 발생합니다. 바라보다"find -exec sh -c"를 사용해도 안전합니까?
기타 참고사항:
- 변수 데이터가 로 시작하지 않을 것이라고 보장할 수 없는 경우 옵션의 끝을 표시하는
-
데 사용합니다 . 지원되는지--
여부는 알 수 없습니다 . 그렇지 않은 경우 관리자에게 버그로 보고할 수 있습니다.ccase
--
- 여기서는 필요하지 않습니다
bash
. 시스템이면sh
충분합니다. - bash와 마찬가지로 sh에서도 매개변수 확장 및 명령 대체는 최소한 목록 컨텍스트에서 인용되어야 합니다. 그렇지 않으면 분할+glob을 거치게 됩니다! 예를 들어 참조하십시오.bash/POSIX 쉘에서 변수를 인용하는 것을 잊어버리는 보안 위험
- 특히 호출과 같이 잠재적으로 파괴적인 작업을 수행하는 경우
mv
실행하는 모든 명령이 성공했는지 확인하는 것이 좋습니다. 여기서는 실패한 디렉터리|| continue
건너뛰기를 사용합니다 .ccase
+
가능한 경우;
여러 디렉터리를 전달 하지 마십시오 .sh
이렇게 하면 파일당 쉘이 호출되는 것을 방지할 수 있습니다. 그러나find
비표준 조건자를 지원 하는 모든 구현이-execdir
그렇게 하는 것은 아닙니다. 일부 BSD나 이전 버전의find
GNU 에서는+
동일한 작업을 수행;
한 후 루핑하는 것이 중복됩니다(비록 무해하긴 하지만).- 에서는 이미 존재하는
mv -- SomeDir some_dir
것과 동일하며some_dir
디렉토리이거나 디렉토리에 대한 심볼릭 링크입니다mv -- SomeDir some_dir/SomeDir
. GNU 구현을 사용하면 옵션을 사용하여 이를 방지mv
할 수 있습니다 (또는 아래 방법을 사용하여 충돌을 감지할 수 있습니다).-T
zmv
이를 방지 -execdir
하고 가능한 한 적은 수의 쉘을 실행하려면 이를 사용할 수 있지만 -exec
기본 이름과 상위 디렉토리를 분리해야 합니다. 개선 사항으로 실패를 기록하여 ccase
종료 상태 mv
에 반영 할 수도 있습니다.find
find . -depth ! -name . -type d -exec sh -c '
ret=0
for dir do
base=${base##*/}
parent=${dir%/*}
new_base=$(ccase -t Kebab -- "$base") && {
[ "$base" = "$new_base" ] ||
mv -i -- "$dir" "$parent/$new_base"
} || ret=$?
done
exit "$ret"' sh {} +
위에서는 예 를 들어 두 파일이 동일한 새 이름으로 끝나는 경우와 같이 데이터 손실을 방지할 수 있는 옵션을 사용자에게 제공하는 옵션을 -i
추가 했습니다 . 더 나은 접근 방식 은 모든 것을 미리 확인하고 시험 실행 모드( ) 를 제공하는 mv
zsh를 사용하는 것입니다 .zmv
-n
autoload -Uz zmv
zmv -n '(**/)(*)(#q/)' '$1$(ccase -t Kebab -- $2)'
또한 기본적으로 숨겨진 파일을 무시합니다. 기본적으로 깊이 우선 순회를 수행합니다. 이 경우 의 (#q/)
종료-type d
상태는 ccase
무시됩니다. 이름이 변경되지 않은 경우 이름 바꾸기가 시도되지 않습니다.
이름에 이미 하이픈이 포함된 파일을 처리하지 않으려면 (*)
바꿀 수 있습니다 .(^*-*)
zsh에서 Kebab 케이스로 변환할 수도 있습니다.
zmv -n '(**/)(*)(#q/)' \
'$1${${${2//[_[:space:]]##/-}//(#b)([^[:upper:].-])([[:upper:]])/$match[1]-$match[2]}:l}'
공백 또는 밑줄의 모든 시퀀스를 단일 문자로 변환하고, 대문자가 아닌 문자( 및 제외)와 기본 이름의 대문자 사이에 s를 삽입 -
하고 전체 결과를 소문자로 변환합니다. 대신 로 이름을 바꾸려면 조정해야 합니다.-
.
-
l
AFileInTheUK.txt
a-file-in-the-u-k.txt
afile-in-the-uk.txt
답변2
디렉터리의 이름을 하나씩 바꾸고 가장 깊은 디렉터리부터 시작합니다. 예를 들어
#!/bin/ksh93
find . -type d -depth -print | while read DIR ; do
PREFIX=${DIR%/*}
SUFFIX=${ ccase -t Kebab "${.sh.match:1}"; }
print mv "${DIR}" "${PREFIX}/${SUFFIX}"
done
그 단어를 삭제하다인쇄스크립트가 요구 사항을 충족하는지 확인한 후 스크립트를 준비하세요 ;-).
답변3
여기 있어요. 내가 찾고 있는 명령은 다음과 같습니다.
find . -depth -type d -execdir bash -c 'mv {} $(ccase -t Kebab {})' \;