디렉터리 아래의 모든 디렉터리 앞에 밑줄 문자를 붙입니다.

디렉터리 아래의 모든 디렉터리 앞에 밑줄 문자를 붙입니다.

이름 시작 부분에 밑줄 "_" 문자를 포함하도록 디렉터리 내의 여러 디렉터리 이름을 바꿔야 합니다.

테스트로서 내용에 세 개의 디렉터리가 포함된 상위 디렉터리를 만들었습니다.

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대상이 이미 존재하는 경우 작업이 거부됩니다.

관련 정보