이름 시작 부분에 밑줄 "_" 문자를 포함하도록 디렉터리 내의 여러 디렉터리 이름을 바꿔야 합니다.
테스트로서 내용에 세 개의 디렉터리가 포함된 상위 디렉터리를 만들었습니다.
dir1, dir2 and dir3; three files: file1, file2, file3
세 개의 점 접두어 파일:
.file1, .file2, .file3
지금까지 다음을 사용하여 Mac에 설치해 보았습니다 gfind
.findutils
gfind . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n" | sh
그러면 다음이 반환됩니다.
mv: rename ./. to ./_.: Invalid argument
그래서 이름 바꾸기 및 찾기를 사용해 보았습니다.
find . -type d -exec rename 's/^/_/' {} \;
그러면 다음이 반환됩니다.
Can't rename '.' to '_.': Invalid argument
Can't rename './dir1' to '_./dir1': No such file or directory
Can't rename './dir2' to '_./dir2': No such file or directory
Can't rename './dir3' to '_./dir3': No such file or directory
누구든지 작동하는 솔루션을 가지고 있거나 내가 잘못될 수 있는 부분을 알고 있습니까?
답변1
내가 올바르게 추측했다면 다음과 같은 파일과 디렉터리가 있을 것입니다.
$ mkdir dir{1,2,3} ; touch file{1,2,3} .file{1,2,3}
$ ls -A
.file1 .file2 .file3 dir1 dir2 dir3 file1 file2 file3
디렉토리 이름을 _dir1
, _dir2
, 로 바꾸고 싶나요 _dir3
?
그것은 find
/ printf mv
실현 가능해 보인다. 그것이 무엇을 인쇄하는지 봅시다:
$ find . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n"
mv "./." "./_."
mv "./dir2" "./_dir2"
mv "./dir3" "./_dir3"
mv "./dir1" "./_dir1"
첫 번째 명령은 "점"이 특별하고 이름을 바꿀 수 없기 때문에 오류를 발생시킵니다. 하지만 다른 것들은 문제가 없으며 필요에 따라 디렉터리 이름을 바꿔야 합니다.
$ find . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n" | sh
mv: cannot move ‘./.’ to ‘./_.’: Device or resource busy
$ ls -d _dir*
_dir1 _dir2 _dir3
그러나 셸에 명령을 파이프하는 것은 약간 보기 흉하며, 파일 이름이 충분히 이상하다면 결과는 놀랄 것입니다(예를 들어 $
셸에서 변수 또는 명령 대체를 트리거하는 기호가 포함된 경우).
파일이 모두 한 수준에 있는 경우 다음을 수행해야 합니다.
for x in * ; do [ -d "$x" ] && mv "$x" "_$x" ; done
_$x
( 이미 존재 하는 경우에도 $x
해당 위치로 이동됩니다.)
이름이 점으로 시작하는 디렉토리를 포함하려면 이를 미리 사용하십시오 shopt -s dotglob
.
이것은 또한 가깝습니다:
find . -type d -exec rename 's/^/_/' {} \;
하지만 로 시작하는 경로가 find
제공되므로 이를 고려해야 합니다. 한 수준에서만 작동합니다(선행을 로 변경 ).rename
./
./
./_
find . -type d -exec rename 's,^./,./_,' {} \;
모든 수준의 디렉토리를 얻으려면 find -execdir
아마도 가장 사용하기 쉬운 방법일 것입니다. 파일 디렉터리에서 명령을 실행합니다. -depth
이름 바꾸기를 올바른 순서로 처리 해야 합니다 .
find . -depth -type d -execdir rename 's,^./,./_,' {} \;
어쩌면 그것도 추가할 수도 있습니다 ! -name .
. 예를 들어
$ mkdir foo foo/dir1 foo/dir2
$ find . -depth \! -name . -type d -execdir rename 's,^./,./_,' {} \;
$ ls _foo
_dir1 _dir2
답변2
첫 번째 시도의 문제점은 .
모든 하위 디렉토리 외에 자체(현재 디렉토리)의 이름을 바꾸려고 한다는 것입니다. 그냥 넘어가.
gfind . -mindepth 1 -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n" | sh
하지만 실제로는 하지 마세요. 절대로 파이프에 물건을 넣지 마십시오 sh
.이건 작동하지 않아파일 이름에 쉘 특수 문자가 포함되어 있지 않은 경우. 이름이 지정된 파일(완전히 유효하지만 특이한 파일 이름) 이 있는 경우 `rm -r ~`
pop은 홈 디렉토리로 이동합니다. -exec
아래와 같이 쉘을 호출합니다 .
_
두 번째 시도는 기본 이름의 시작 부분, 즉 마지막에 추가하는 대신 전체 경로의 시작 부분에 삽입하기 때문에 작동하지 않습니다 /
.
find . -mindepth 1 -type d -exec rename 's![^/]+$!_$&!' {} \;
중첩된 디렉토리가 있는 경우 이들 중 어느 것도 실제로 작동하지 않습니다. find
탐색할 때 디렉토리 이름이 바뀌기 때문입니다. 이렇게 하면 이 -depth
옵션을 사용하여 디렉터리 자체에 대해 작업을 수행하기 전에 디렉터리의 내용에 대해 작업을 수행해야 합니다.
find . -mindepth 1 -depth -type d -exec rename 's![^/]+$!_$&!' {} \;
보다 편리하게는 쉘을 호출하고 mv
. 이는 모든 POSIX 시스템에 적용됩니다.
find . -depth -type d -name . -o -exec sh -c '
for d do mv "$d" "${d%/*}/_${d##*/}"; done
' sh {} +
중첩된 하위 디렉터리가 없으면 간단한 셸 루프를 사용할 수 있습니다. 점으로 시작하는 디렉토리 이름을 바꾸지 않으려면 와일드카드를 사용하세요. 와일드카드 */
는 디렉토리 및 디렉토리에 대한 심볼릭 링크만 일치시킵니다.
for d in */; do
if [ "$d" = "*/* ] && [ ! -e "$d" ]; then continue; fi # robustness in case there are no subdirectories
if [ -L "$d" ]; then continue; fi # optional: skip symbolic links to directories
mv -- "$d" "_${d%/}"
done
이름이 점으로 시작하는 디렉터리를 포함하여 모든 디렉터리의 이름을 바꾸려면 .*
와일드카드 문자도 포함하십시오.
for d in .*/ */; do
if [ "$d" = "*/* ] && [ ! -e "$d" ]; then continue; fi
if [ -L "$d" ]; then continue; fi
mv -- "$d" "_${d%/}"
done
foo
로 이동할 때 이라는 _foo
디렉터리가 이미 있는 경우 이전 디렉터리 는 으로 _foo
이동됩니다 . 이를 방지하려면 명시적 테스트를 추가하세요.foo
_foo/foo
또는 zsh를 사용할 수도 있습니다. macOS에는 사전 설치되어 제공됩니다. 처음으로 실행하여 autoload -U zmv
(귀하의 스크립트에 넣어서 .zshrc
) 로드하세요.zmv
기능, 비재귀 버전(심볼릭 링크를 제외한 도트 파일 포함)은 다음 (/D)
과 같은 집합입니다.글로벌 예선):
zmv -Q '*(/D)' '_$f'
또는 재귀 버전(사용수정자디렉터리 이름과 기본 이름 추출:
zmv -Q '**/*(/D)' '$f:h/_$f:t'
zmv
대상이 이미 존재하는 경우 작업이 거부됩니다.