bash 또는 zshell과 같은 셸을 사용하여 재귀적인 ‘찾기 및 바꾸기’를 수행하려면 어떻게해야합니까? 즉,이 디렉토리와 하위 디렉토리의 모든 파일에서 모든 ‘foo’발생을 ‘bar’로 바꾸고 싶습니다.
답변
이 명령은 Mac OS X Lion 및 Kubuntu Linux에서 테스트됩니다.
# Recursively find and replace in files
find . -type f -name "*.txt" -print0 | xargs -0 sed -i '' -e 's/foo/bar/g'
작동 방식은 다음과 같습니다.
find . -type f -name '*.txt'
현재 디렉토리 (.
) 이하에서-type f
이름이 끝나는 모든 일반 파일 ( )을 찾습니다 ..txt
|
해당 명령의 출력 (파일 이름 목록)을 다음 명령으로 전달합니다.xargs
그 파일 이름을 모아 하나씩sed
sed -i '' -e 's/foo/bar/g'
“백업없이 파일을 제자리에서 편집하고 한s/foo/bar
줄에 여러 번 대체 (/g
)를 수행합니다”(man sed
)
변경하는 파일은 버전 관리를 받고 있기 때문에 4 행의 ‘백업없이’부분은 괜찮습니다. 따라서 실수가있을 경우 쉽게 취소 할 수 있습니다.
답변
find . -type f -name "*.txt" -exec sed -i'' -e 's/foo/bar/g' {} +
이것은 xargs
의존성을 제거합니다 .
답변
Git을 사용하는 경우 다음을 수행 할 수 있습니다.
git grep -lz foo | xargs -0 sed -i '' -e 's/foo/bar/g'
-l
파일 이름 만 나열합니다. -z
각 결과 뒤에 널 바이트를 인쇄합니다.
프로젝트의 일부 파일에는 파일 끝에 줄 바꿈이 없기 때문에이 작업을 끝내고 다른 변경 사항이 없어도 줄 바꿈을 추가했습니다. (파일 끝에 줄 바꿈이 있어야하는지에 대한 의견은 없습니다. ?)
답변
여기에 내가 사용하는 zsh / perl 함수가 있습니다.
change () {
from=$1
shift
to=$1
shift
for file in $*
do
perl -i.bak -p -e "s{$from}{$to}g;" $file
echo "Changing $from to $to in $file"
done
}
그리고 나는 그것을 사용하여 그것을 실행할 것이다.
$ change foo bar **/*.java
(예를 들어)
답변
시험:
sed -i 's/foo/bar/g' $(find . -type f)
우분투 12.04에서 테스트되었습니다.
서브 디렉토리 이름 및 / 또는 파일 이름에 공백이 있으면이 명령이 작동하지 않지만이를 사용하면 작동하지 않으므로이 명령을 사용하지 마십시오.
일반적으로 디렉토리 이름과 파일 이름에 공백을 사용하는 것은 좋지 않습니다.
http://linuxcommand.org/lc3_lts0020.php
“파일 이름에 대한 중요한 사실”을보십시오
답변
이 셸 스크립트 사용
이제 다른 답변과 웹 검색에서 배운 내용을 결합한이 셸 스크립트를 사용합니다. 나는라는 파일에 배치 change
내에서 폴더 $PATH
및했다 chmod +x change
.
#!/bin/bash
function err_echo {
>&2 echo "$1"
}
function usage {
err_echo "usage:"
err_echo ' change old new foo.txt'
err_echo ' change old new foo.txt *.html'
err_echo ' change old new **\*.txt'
exit 1
}
[ $# -eq 0 ] && err_echo "No args given" && usage
old_val=$1
shift
new_val=$1
shift
files=$* # the rest of the arguments
[ -z "$old_val" ] && err_echo "No old value given" && usage
[ -z "$new_val" ] && err_echo "No new value given" && usage
[ -z "$files" ] && err_echo "No filenames given" && usage
for file in $files; do
sed -i '' -e "s/$old_val/$new_val/g" $file
done
답변
내 유스 케이스로 교체 foo:/Drive_Letter
하고 싶었
습니다 foo:/bar/baz/xyz
. 내 경우에는 다음 코드로 처리 할 수있었습니다. 대량의 파일이 있던 동일한 디렉토리 위치에있었습니다.
find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'
도움이 되었기를 바랍니다.