모든 디렉토리와 파일의 이름을 바꾸고 공백을 제거하는 스크립트가 있습니다. 재귀적으로 실행됩니다:
#!/bin/bash
find -name "* *" -print0 | sort -rz | \
while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
~
스크립트를 디렉터리에서 실행할 때 다음 프로젝트의 이름이 예기치 않게 변경되었습니다.
./.cache/google-chrome/Default/Storage/ext/nmmhkkegccagdldgiimedpiccmgmieda/def/Code Cache
./.cache/google-chrome/Default/Storage/ext/gfdkimpbcpahaombhbimeihdjnejgicl/def/Code Cache
./.cache/google-chrome/Default/Code Cache
.
내 스크립트 에서 이름 바꾸기로 시작하는 모든 디렉터리나 파일을 제외하고 싶습니다 . 이런 스크립트를 어떻게 작성하시겠어요? 이 목적을 위해 정규식을 사용해야 합니까?
답변1
파이프라인의 다른 명령을 너무 많이 살펴보지 않고도 find
숨겨진 이름이 있는 디렉터리를 입력하지 않아도 됩니다.
find . ! -path . -name '.*' -prune -o -name '* *' -print0 | ...
이렇게 하면 디렉터리(현재 디렉터리)를 제외하고 .
검색 트리에서 이름으로 시작하는 모든 디렉터리가 제거 됩니다. .
또한 더 이상 숨겨진 이름을 찾지 않습니다.
코드의 나머지 부분을 살펴본 후 rename
(Perl 변형)을 사용하는 것이 좋습니다.
find . ! -path . -name '.*' -prune \
-o -type f -name '* *' -execdir rename -n -v 'tr/ /_/' {} \;
공백이 포함된 파일 이름을 검색한 다음 숨겨진 이름을 무시하고 숨겨진 디렉터리를 입력하지 않고 공백을 밑줄로 바꿉니다.
rename
-n
실제로 어떤 작업도 수행하지 못하도록 유틸리티를 호출합니다 ("시험 실행"입니다). -n
올바른 작업을 수행하고 있다고 확신하면 제거하십시오.
그렇지 않다면 rename
다음과 같은 일을 할 것입니다.
find . ! -path . -name '.*' -prune \
-o -type f -name '* *' -exec bash -c '
for pathname do
filename=${pathname##*/}
echo mv "$pathname" "${pathname%/*}/${filename// /_}"
done' bash {} +
즉, bash
발견된 이름을 반복하여 공백을 밑줄로 변경하여 각 이름을 바꾸는 인라인 스크립트가 호출됩니다.
echo
그것이 옳은 일이라고 확신할 때 삭제하십시오.
답변2
그냥 zsh
사용하십시오 zmv
:
#! /bin/zsh -
autoload -Uz zmv
zmv '(**/)(* *)' '$1${2// /_}'
zmv
숨겨진 파일과 숨겨진 디렉터리의 파일은 기본적으로 건너뜁니다((#qD)
첫 번째 인수에 한정자를 전달하지 않는 한).- 파일을 처리합니다깊이 우선(
sort -rz
이 기능이 작동할 것이라는 보장은 없으며-prune
호환되지 않습니다-depth
.) dirname
/를 호출할 필요가 없습니다basename
(개행으로 끝나는 파일 이름이 있는 경우 비용이 많이 들고 명령 대체가 제대로 작동하지 않습니다).- 임의의 바이트 시퀀스가 일치하지 않는 문제가 없습니다
find
.*
- 충돌이 있는 경우(예: a
a b c
와a_b c
파일 이름이 모두 바뀌는 경우a_b_c
) 처음부터 충돌을 감지하고 이름을 바꾸기 전에 중단합니다.
GNU 도구를 사용하여 다음과 같은 작업을 수행하려면:
#! /bin/bash -
export LC_ALL=C
while IFS= read <&3 -rd '' file; do
dir=${file%/*} name=${file##*/}
mv -i -- "$file" "$dir/${name// /_}"
done 3< <(
find . -name '.?*' -prune -o -name '* *' -print0 |
tac -s '')
여기,
- 로케일을 로 설정하면
C
사용자*
로케일에서 유효한 문자를 형성하는 바이트뿐만 아니라 모든 바이트 시퀀스와 일치하고?
단일 바이트와 일치합니다. 하지만 메시지(오류, 프롬프트...)는 사용자의 언어가 아닌 영어로 전송된다는 점에 유의하세요. -name '.?*' -prune -o ...
숨겨진 파일을 건너뛰고find
숨겨진 디렉터리에 들어가지 않도록 지시합니다.- 실수로 인한 파일 손상을 방지하기
-i
위해 전달됩니다 .mv
- stdin 대신 fd 3을 통해 파일 목록을 전달하면
mv -i
프롬프트가 작동합니다. tac -s ''
대체를 사용하여sort -rz
출력을 반전시켜 나뭇잎이 있는 가지보다 먼저 이름이 바뀌도록 하세요.dirname
/를basename
표준${var##pattern}
및${var%pattern}
매개변수 확장 연산자로 바꾸세요.- 또한 백슬래시의 특수 처리를 비활성화
-r
하려면 를 전달하십시오.read
read
$IFS
입력 레코드에서 후행 공백이 제거되지 않도록 가 비어 있는지 확인하세요 .