모든 디렉터리 및 파일 이름의 문자열을 재귀적으로 바꾸는 클리너 스크립트

모든 디렉터리 및 파일 이름의 문자열을 재귀적으로 바꾸는 클리너 스크립트

모든 디렉터리 및 파일 이름의 문자열을 다른 문자열로 재귀적으로 바꾸고 싶습니다. 따라서 foo를 bar로 바꾸고 이 파일을 갖고 싶다면:

 foo_project/my_app/old_foo/start_foo.sh

나는 그것을 원한다

 bar_project/my_app/old_bar/start_bar.sh

나는 이것을 할 수 있었지만 매우 추악합니다. 메모리에서 쓰기(복사 및 붙여넣기가 불가능하므로 오타를 용서해 주세요) 내 명령은 다음과 같습니다.

find $PROJECT_DIR -name "*foo*" | tac | xargs -n 1 -I % bash -c "eval mv % \$\( echo % \| sed \''s/\(.*\)foo/\1$PROJECT_NAME/'\' \)"

이것은 나에게 효과적이지만 끔찍합니다. 내가 원하는 것을 더 깔끔하게 수행할 수 있는 방법이 있나요?

위 명령에 대한 컨텍스트를 제공하기 위해 이전 rename 명령이 경로를 다르게 만들어 나중에 mv 명령을 중단한다는 문제가 있었습니다. 그렇기 때문에 가장 깊게 중첩된 이름 바꾸기를 먼저 실행했는지 확인하기 위해 xargs 전에(시작하기 위한 -evalcmd 인수 대신) tac로 전환했습니다. 그런 다음 sed의 이름을 바꾸도록 해야 했습니다.마지막이름을 바꾸기 전에 폴더 안의 모든 항목을 이동할 수 있도록 foo의 인스턴스입니다.

추악한 부분은 eval이 필요하므로 xargs의 내용을 sed 명령에 전달하는 방법을 모르기 때문에 여러 수준의 매개 변수 이스케이프가 필요하다는 것입니다. 그래도 뭔가 더 깔끔해야겠죠?

답변1

renameCentOS 또는 CentOS가 없는 일부 시스템 (때때로 호출됨 prename) 을 사용하는 경우반복 제안보기 좋은 곳입니다. Debian 파생 제품을 사용하는 경우 다음과 같은 방법도 도움이 될 수 있습니다.

find "$PROJECT_DIR" -depth -type d -execdir echo rename 's/foo/bar/' {} +

그러면 디렉토리 트리가 삭제됩니다.깊이 우선각 디렉토리의 모든 프로젝트 이름을 각 인스턴스에서 로 변경합니다 foo.bar

(실제로는 어떻게 될지 보여주는 것 외에는 아무것도 하지 않습니다. echo만족스러우면 제거하세요...)

답변2

이와 같이 잠재적으로 까다롭고 위험할 수 있는 작업의 경우 원하는 작업을 수행하는 스크립트를 생성하는 것을 좋아합니다.

$ find foo_project -print > /tmp/list
$ vi /tmp/list
:%s/.*/'&'/            # quote all filenames just to be safe
:%s/.*/mv & &/         # generate mv commands
:%s/' '/'\r'/          # break them for the next step
:v/^mv /s/foo/bar/g    # modify the second arguments
:g/^mv /j              # re-join the lines

이제 잠시 시간을 내어 방금 생성한 스크립트를 검토하여 원하는 대로 작동하는지 확인하세요.

mv 'foo_project/my_app/old_foo/start_foo.sh' 'bar_project/my_app/old_bar/start_bar.sh'
...

네가 이것을 좋아한다면:

:wq
$ sh /tmp/list

이것은 제가 항상 사용하는 일반적인 기술입니다. 스크립트를 편집하는 정확한 방법은 수행하려는 작업에 따라 다릅니다. 섹시한 농담은 아니지만 안전합니다.

이제 이것이 일회성 작업이 아닌 정기적으로 수행하려는 작업이라면 이 기술은 원하는 것이 아닐 수도 있습니다. 그러나 일회성 작업(느낌으로 수행해야 하는 경우)의 경우 이는 훌륭하게 작동합니다.

이제 재사용 가능한 솔루션을 원한다면 스크립트를 작성해야 합니다.

#!/bin/sh
find foo_project -print | while read filename; do
  newname=`echo $filename | sed -e 's/foo/bar/g'`
  echo "renaming $filename => $newname"
  mv "$filename" "$newname"
done

관련 정보