코드가 Java이고 Eclipse 플러그인이라는 사실은 중요하지 않지만 Eclipse 플러그인 프로젝트에서 전역적으로 이름을 변경해야 했습니다.
기본적으로 수행해야 할 단계는 다음과 같습니다.
find . -name "*" -type f | grep -v \.git | xargs sed -i 's/com.foo/org.bar/g
- 모든 디렉토리( 제외
.git
) 에 대해src/com
이름을 다음으로 바꿉니다.src/org
- 모든 디렉토리( 제외
.git
) 에 대해src/org/foo
이름을 다음으로 바꿉니다.src/org/bar
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 -path
은 find d -not -path '*.git*' -type f
5개의 파일만 일치합니다.
$ 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
공백이 포함된 경로에서는 작동하지 않거나 \'"
입력을 및 사이의 문자로 바꿉니다. 마지막 문제는 점 앞에 백슬래시를 추가하면 쉽게 해결됩니다. 파일 이름 문제는 설정에서 문제가 될 수도 있고 아닐 수도 있습니다. 소스 트리는 꽤 길들여지는 경향이 있습니다. 또한 중복됩니다(항상 일치함). 이는 하위 트리를 올바르게 생략하는 안전하고 간단한 대안입니다.com
foo
-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를 사용하여 파일 이름 바꾸기
짐zmv
function 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'