1

1

코드가 Java이고 Eclipse 플러그인이라는 사실은 중요하지 않지만 Eclipse 플러그인 프로젝트에서 전역적으로 이름을 변경해야 했습니다.

기본적으로 수행해야 할 단계는 다음과 같습니다.

  1. find . -name "*" -type f | grep -v \.git | xargs sed -i 's/com.foo/org.bar/g
  2. 모든 디렉토리( 제외 .git) 에 대해 src/com이름을 다음으로 바꿉니다.src/org
  3. 모든 디렉토리( 제외 .git) 에 대해 src/org/foo이름을 다음으로 바꿉니다.src/org/bar
  4. com.foo이름에 포함된 모든 파일 및 디렉터리 이름(.git 제외)에 대해 이 섹션을 org.bar.

첫 번째 단계에 대한 명시적인 명령줄만 있습니다.

다른 단계를 반수동으로 수행할 수도 있지만 이를 수행하는 자동화된 방법을 찾는 것이 가치가 있다고 생각합니다. 2단계와 3단계는 동일하지만 4단계는 다릅니다.

나는 순수한 bash 명령줄을 사용하여 이 작업을 수행하고 싶지만 간단한 bash나 perl 스크립트를 사용해도 됩니다.

고쳐 쓰다:

사실, 나는 단지 src/com. 나는 여전히 src/main/java/com과 가 필요합니다 src/test/java/com.

이를 위해 나는 다음과 같은 노력을 해왔습니다.

find . -type d -name "com" | grep "\(/src/com\|/src/main/java/com\|/src/test/java/com\)" | xargs -n1 -i{} echo mv {} $(echo {} | sed -e 's/com/org/g')

비슷하지만 마지막 항목이 sed일치하지 않으므로 변경되지 않습니다. 결과는 다음과 같습니다.

mv ./plugins/.../src/com ./plugins/.../src/com

답변1

1

*첫 번째 단계의 경우 명령 예제에서는 파일을 필터링하지 않으므로 필요하지 않습니다 . 당신이 해야 할 일은 .git다음과 같이 필터링하는 것입니다.

$ find . -name '.git' -prune -o -type f -print

-prune이는 완전한 이름의 디렉토리 와 그 안에 있는 모든 내용을 거부( )합니다 .git.

grep -v ".git"이는 sed가 파일 내부를 편집하고 있기 때문에 피할 수 없다는 사실을 없애줍니다 . 이는 find가 할 수 없는 작업입니다.

하지만 여전히 단순화할 수 있습니다(sed에서 요점을 인용하기 위해).

$ find . -name '.git' -prune -o -type f -exec sed -i 's/com\.foo/org\.bar/g' '{}' \+

이는 파일 이름(xargs와 유사)을 sed명령에 축적합니다.

하지만 더 나은 점은 다음과 같습니다.

$ find . -name '.git' -prune -o -type f -execdir sed -i 's/com\.foo/org\.bar/g' '{}' \+

그러면 디렉터리당 하나의 sed 인스턴스가 실행됩니다.

2, 3

디렉터리 이름 바꾸기를 수행하는 함수를 정의해 보겠습니다.

$ renamedir (){ find "$1" -name '.git' -prune -o -type d -exec bash -c 'mv "$1" "${1//"$2"/$3}"' sh '{}' "$2" "$3" \; ; }

2 단계:

  • src/com(.git 제외)의 모든 디렉터리 이름을 src/org로 바꿉니다.

    $ renamedir 'd/src/com' 'src/com' 'src/org'
    

3단계:

  • src/org/foo(.git 제외)의 모든 디렉터리 이름을 src/org/bar로 바꿉니다.

    $ renamedir 'src/org/foo' 'ogr/foo' 'org/bar'
    

4

4단계:

  • 이름에 "com.foo"가 포함된 모든 파일 및 디렉터리 이름(.git 제외)의 경우 해당 부분을 "org.bar"로 변경합니다.

    $ find . -name '.git' -prune -o -name "com.foo" -type f -exec bash -c 'mv "$1" "${1//"$2"/$3}"' sh '{}' "com.foo" "org.bar" \; ; }
    

모두 (더 나은 형식의) 스크립트 안에 있습니다:

#!/bin/bash

# NOTE: There are three echo to avoid execution of commands.
#       If after testing, you decide that it is ok to execute commands,
#       remove the echo words.

# Step 1:
### for all files (excluding .git) in . change
###     file contents from com.foo to org.bar
find . -name '.git' -prune -o -type f -execdir echo sed -i 's/com\.foo/org\.bar/g' '{}' \+

renamedir (){ find "$1" -name '.git' -prune -o -type d -exec bash -c '
                  echo \
                  mv "$1" "${1//"$2"/$3}"
              ' sh '{}' "$2" "$3" \;
        }

# Step 2:
### for all directories (excluding .git) in src/com rename to src/org
renamedir 'd/src/com' 'src/com' 'src/org'

# Step 3:
### for all directories (excluding .git) in src/org/foo rename to src/org/bar
renamedir 'src/org/foo' 'org/foo' 'org/bar'

# Step 4:
### for all file and directory names (excluding .git)
### with "com.foo" in the name, change that portion to "org.bar".
find . -name '.git' -prune -o -name "*com.foo*" -type f -exec bash -c '
    echo \
    mv "$1" "${1//"$2"/$3}"
' sh '{}' "com.foo" "org.bar" \; ; }

일치의 다른 버전을 테스트하려면 다음과 같은 완전한 파일 트리를 만듭니다(나중에 삭제하는 데 사용 rm -rf ./d/).

$ mkdir -p d/src/{{,.git}{,one},com/{{,.git}{,two},\ .git,.git/six},org/{{,.git}{,three},bar/{,.git}{,four},foo/{,.git}{,five}}}
$ touch d/src/{111,com/{222,.git/666},org/{333,bar/444,foo/555}}  
$ touch d/src/{.git/{aaa,one/aaaaa},one/aaa111,com/.git{/bbb,two/bbb222},org/{.git{/ccc,three/ccc333},bar/.git{/ddd,four/ddd444},foo/.git{/eee,five/eee555}}}               

원래 명령(GNU -z 옵션을 사용하여 find -print0과 일치)은 다음과 일치합니다(이 디렉터리에서).

$ find d/ -type f -print0 | grep -zZv \.git
find d/ -type f -print0 | grep -zZv \.git | xargs -0 printf '<%s>\n'
<d/src/org/333>
<d/src/org/foo/555>
<d/src/org/bar/444>
<d/src/com/222>
<d/src/111>

아무 관련도 없는 파일은 5개뿐입니다 .git.


일반적으로 말하면:

.git, 및 에는 세 가지 주요 일치 방법이 있습니다 find. 이상한 점(emacs 정규식 사용)과는 별개로 여기서는 필요하지 않은 복잡한 일치만 필요합니다.-name-regex-path-regex

A는 find d/ -path "./.git"정확히 일치합니다. 즉, 중간 디렉터리가 하나만 있습니다 .git.
또는 (생성된 디렉터리의 경우) find . -path './d/src/.git'다음과만 일치합니다../d/src/.git

A는 트리의 마지막 수준(기본 이름)에서 find d/ -name ".git"정확히 일치합니다 ..git

-name "*.git"및 둘 다 -path "*.git"정확히 일치합니다.
임의의 문자열마치다존재하다 .git.

두 개의 별표를 추가하면 상황이 복잡해지기 시작합니다. *.git*
이 경우 -name경로의 마지막 수준(파일의 기본 이름)만 일치하지만 두 개의 별표는 *접두사가 있는 이름과도 일치하므로(공백에 유의하세요) .git그리고 접미사(많은 유사점에 주목하세요 .gitone):

$ find d -name '*.git*'
d/src/org/.gitthree
d/src/org/foo/.git
d/src/org/foo/.gitfive
d/src/org/bar/.gitfour
d/src/org/bar/.git
d/src/org/.git
d/src/com/.gittwo
d/src/com/.git
d/src/com/ .git
d/src/.git
d/src/.gitone

.git거의 grep과 마찬가지로 경로의 모든 수준에서 일치합니다 . grep은 복잡한 정규 표현식을 가질 수 있으므로 grep과 정확히 동일하지는 않지만 여기서 일치하는 것은 단순한 "패턴"에 대한 것입니다. d/src/com/.git/six다음 사항에 유의하세요 .

$ find d -path '*.git*'
d/src/org/.gitthree
d/src/org/foo/.git
d/src/org/foo/.gitfive
d/src/org/bar/.gitfour
d/src/org/bar/.git
d/src/org/.git
d/src/com/.gittwo
d/src/com/.git
d/src/com/.git/six
d/src/com/ .git
d/src/.git
d/src/.gitone

그런 다음 여러 가지 방법으로 이러한 일치 항목을 수정할 수 있습니다. ( not또는 !)를 사용하면 다음 일치 항목이 거부됩니다.

아니요(!)

find d -name '.git'일치하는 경우 :

d/src/org/foo/.git
d/src/org/bar/.git
d/src/org/.git
d/src/com/.git
d/src/.git

그런 다음 find d -not -name '.git'(또는 정확히 동일하게 find d ! -name '.git': ) 다른 모든 항목과 일치합니다. 목록이 매우 길기 때문에 여기에 인쇄되지 않습니다.

그러나 파일만 선택하는 것은 간단합니다(참고 파일 666).

$ find d -not -name '.git' -type f
d/src/org/333
d/src/org/foo/555
d/src/org/bar/444
d/src/com/222
d/src/com/.git/666
d/src/111

in -pathfind d -not -path '*.git*' -type f5개의 파일만 일치합니다.

$ find d -not -path '*.git*' -type f
d/src/org/333
d/src/org/foo/555
d/src/org/bar/444
d/src/com/222
d/src/111

치다

-prune또는 모든 디렉토리를 "잘라내기" 또는 "삭제" 할 수 있습니다.더 일찍허용되는 일치 항목:

$ find d \( -name '.git' -prune \) -o \( -print \)
d
d/src
d/src/org
d/src/org/three
d/src/org/333
d/src/org/.gitthree
d/src/org/foo
d/src/org/foo/five
d/src/org/foo/555
d/src/org/foo/.gitfive
d/src/org/bar
d/src/org/bar/.gitfour
d/src/org/bar/four
d/src/org/bar/444
d/src/one
d/src/com
d/src/com/.gittwo
d/src/com/222
d/src/com/two
d/src/com/ .git
d/src/111
d/src/.gitone

- 가지치기 후에 뭔가가 있을 거에요. 일반적으로 "-o"는 -print자두가 일치하지 않는 항목과 일치하는 또 다른 하나입니다 . 보시다시피 이는 명령의 5개 파일보다 더 많은 파일과 일치합니다. delete 만 사용 '.git'하도록 변경되었습니다 . 그러나 사용하는 것은 grep에 더 가깝습니다(여전히 동일하지는 않습니다).'*.git'd/src/com/ .git'*.git*'

$ find d \( -name '*.git*' -prune \) -o \( -print \)
d
d/src
d/src/org
d/src/org/three
d/src/org/333
d/src/org/foo
d/src/org/foo/five
d/src/org/foo/555
d/src/org/bar
d/src/org/bar/four
d/src/org/bar/444
d/src/one
d/src/com
d/src/com/222
d/src/com/two
d/src/111

이는 명령의 5개 파일(디렉토리 아님)에만 일치합니다.

$ find d \( -name '*.git*' -prune \) -o \( -type f -print \)

이는 또한 처음 5개 파일과만 일치합니다. 추가하면 -type f많은 세부 정보가 숨겨집니다.

$  find d \( -name '.git' -prune \) -o \( -type f -print \)

일반적으로 괄호가 없습니다(너무 명확하지 않음).

$ find d -name '.git' -prune -o -type f -print

경고: 삭제하면 -print의도하지 않은 부작용이 발생할 수 있습니다.

답변2

파일에서 바꾸기

주문여러 가지 이유로 신뢰할 수 없음: 하위 문자열이 포함된 모든 경로를 제외하고 .git공백이 포함된 경로에서는 작동하지 않거나 \'"입력을 및 사이의 문자로 바꿉니다. 마지막 문제는 점 앞에 백슬래시를 추가하면 쉽게 해결됩니다. 파일 이름 문제는 설정에서 문제가 될 수도 있고 아닐 수도 있습니다. 소스 트리는 꽤 길들여지는 경향이 있습니다. 또한 중복됩니다(항상 일치함). 이는 하위 트리를 올바르게 생략하는 안전하고 간단한 대안입니다.comfoo-name "*".git

find . -name .git -prune -o -type f -exec sed -i 's/com\.foo/org.bar/g' {} +

예를 들어 , 이런 일이 발생하는 경우 권장되지 않을 com.fooalso수 있는 대신 이 방법이 여전히 사용됩니다 . org.baralso이것은 더 안전한 구조입니다.

find . -name .git -prune -o -type f -exec sed -i -e 's/com\.foo$/org.bar/' -e 's/com\.foo\([^-_0-9A-Za-z]\)/org.bar\1/' {} +

zsh를 사용하여 파일 이름 바꾸기

zmvfunction autoload -U zmv, 파일 이름을 바꾸는 데 사용할 수 있습니다.와일드카드 패턴. 내 생각엔 당신이 찾고 있는 것이 실제로는

zmv -w '**/com/foo' '$1/org/bar'
zmv -w '**/*com.foo' '$1/${2}org.bar'
zmv '(**/)(*)com.foo([^-_0-9A-Za-z]*)' '$1${2}org.bar$3'

관련 정보