grep 및 교체 방법


251

디렉토리의 모든 파일과 하위 디렉토리에서 지정된 문자열을 재귀 적으로 검색하고이 문자열을 다른 문자열로 바꿔야합니다.

나는 그것을 찾는 명령이 다음과 같다는 것을 알고 있습니다.

grep 'string_to_find' -r ./*

그러나 모든 인스턴스 string_to_find를 다른 문자열로 어떻게 바꿀 수 있습니까?


나는 grep이 이것을 할 수 있다고 믿지 않는다 (나는 틀렸다). 보다 쉬운 방법은 sed 또는 perl을 사용하여 교체 작업을 수행하는 것입니다.
Memento Mori

2
사용하려고sed -i 's/.*substring.*/replace/'
Eddy_Em

2
@Eddy_Em 전체 줄을 replace로 바꿉니다. 부분 문자열 앞뒤에있는 줄의 일부를 캡처하려면이를 그룹화를 사용하여 교체 줄에 넣어야합니다. sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
JStrahl


답변:


248

또 다른 옵션은 find를 사용한 다음 sed를 통해 전달하는 것입니다.

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \;

34
OS X 10.10 터미널에서는 매개 변수에 대한 적절한 확장 문자열 -i이 필요합니다. 예를 들어, find /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;어쨌든 빈 문자열을 제공하면 매뉴얼에 설명 된 것과 달리 여전히 백업 파일이 생성됩니다.
Eonil

10
"sed : RE 오류 : 잘못된 바이트 시퀀스"가 표시되는 이유는 무엇입니까? 그리고 예, -i ""OS X 용을 추가했습니다 . 그렇지 않으면 작동합니다.
taco

2
macOS 10.12에서 잘못된 바이트 시퀀스 문제가 있었고이 질문 / 답변이 내 문제를 해결했습니다 : stackoverflow.com/questions/19242275/… .
abeboparebop

3
파일 시간이 수정되도록 모든 파일을 터치합니다. 및 변환은 엔딩 라인 CRLF으로 LFWindows에서.
jww

183

나는 대답을 얻었다.

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'

14
일치하는 파일을 두 번 스캔 grep합니다 sed. find방법을 사용 하는 것이 더 효율적이지만 언급 한이 방법이 효과적입니다.
cmevoli

41
OS X에서 당신은 변경해야합니다 sed -i 's/str1/str2/g'으로 sed -i "" 's/str1/str2/g'이 작업을 수행하려면.
jdf

6
이 방법을 사용하는 @cmevoli는 grep모든 파일을 살펴보고 sed일치하는 파일 만 검색합니다 grep. find다른 답변 의 방법으로 find먼저 모든 파일을 나열한 다음 sed해당 디렉토리의 모든 파일을 스캔합니다. 따라서이 방법은 반드시 속도가 느릴 필요는 없습니다. 일치하는 횟수와 sed, grep및 사이의 검색 속도 차이에 따라 다릅니다 find.
joelostblom

4
OTOH이 방법은 발견이 전 실제로 특히 자신과 같은 정규식 n00bs을 위해 크게 실패의 위험을 감소, 대체 grep으로 무엇을 미리 볼 수 있습니다
레나 롤랑

2
이것은 grep 교체가 sed보다 더 영리한 경우에도 유용합니다. 예를 들어 ripgrep은 .gitignore에 따르지만 sed는 그렇지 않습니다.
user31389

43

다음과 같이 할 수도 있습니다.

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

현재 디렉토리와 관련된 모든 파일에서 문자열 ' windows '를 검색하고 각 파일에서 문자열이 나타날 때마다 ' windows '를 ' linux '로 바꿉니다 .


2
grep수정할 수 없습니다 파일이있는 경우에만 유용합니다. sed모든 파일에서 실행 하면 파일의 수정 날짜가 업데이트되지만 일치하는 내용이 없으면 내용이 변경되지 않습니다.
tripleee

@tripleee :주의해야 하지만 ... [sed] 일치하는 항목이 없으면 내용을 변경하지 않은 채로 두십시오 " . 사용 하면 내용이 변경되지 않아도 터치하는 모든 파일의 파일 시간이 변경 -i된다고 생각 sed합니다. sed또한 줄 끝을 변환합니다 . 나는 사용하지 않는 sed모든 때문에 망할 놈의 repo에서 Windows에서 CRLF변경됩니다 LF.
jww

이 명령은 -i 뒤에 ""가 필요하며 적어도 macosx에서 전체 대체가 수행 된 후 백업 파일이 작성되지 않음을 표시합니다. 자세한 내용은 매뉴얼 페이지를 확인하십시오. 백업을 원할 경우 파일 확장자를 생성 할 위치입니다.
spinyBabbler

31

이것은 OS X에서 가장 효과적입니다.

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi

출처 : http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files


이것은 완벽 해요! 또한 ag와 함께 작동합니다.ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi

@sebastiankeller Perl 명령에는 마지막 슬래시가 없으며 구문 오류입니다.
tripleee

3
sort -u이것 의 짝수 부분입니까? 어떤 상황 grep -rl에서 동일한 파일 이름을 두 번 생성 할 것으로 예상 됩니까?
tripleee

5

다른 솔루션은 정규식 구문을 혼합합니다. 검색과 바꾸기 모두에 perl / PCRE 패턴을 사용 하고 일치하는 파일 만 처리하려면 다음과 같이 작동합니다.

grep -rlZPi 'match1' | xargs -0r perl -pi -e 's/match2/replace/gi;'

여기서 match1과은 match2일반적으로 동일하지만 match1, 예를 들어 캡처 그룹 대체에만 관련된 고급 기능을 제거하기 위해 단순화 할 수있다.

번역 : grep이 PCRE 패턴과 일치하는 파일을 재귀 적으로 나열하고 파일 이름의 특수 문자를 보호하기 위해 nul로 구분 한 다음 파일 이름이 널 xargs분리 목록이 필요한 파일 이름을 파이프 하지만 이름이 수신되지 않으면 아무 것도 수행하지 않습니다. 얻을 perl일치가 발견 라인을 대체 할 수 있습니다.

이진 파일을 무시 하려면 I스위치를 추가하십시오 grep. 대소 문자 매칭 드롭 i전환 grepi대체 식 부착 플래그하지만 하지i 에 스위치 perl자체.


Perl 자체는 파일 구조를 되풀이 할 수 있습니다. 사실, find2perlPerl과 함께 제공 되는 도구 가 xargs있습니다.
tripleee

@tripleee find는 파일 내용을 검색하지 않으며 요점은 Perl 프로그램을 작성하지 않고 일치하는 파일 만 처리하는 것입니다.
Walf

이것은 sed 기반 솔루션의 줄 끝 변환 문제를 피하기 때문에 Windows에 좋은 솔루션입니다. 감사!
JamHandy

4

일반적으로 grep이 아니라 sed -i 's/string_to_find/another_string/g'또는을 사용 perl -i.bak -pe 's/string_to_find/another_string/g'합니다.


3

사용할 때 매우 조심 find하고 sed힘내의 repo에! 이진 파일을 제외하지 않으면이 오류가 발생할 수 있습니다.

error: bad index file sha1 signature 
fatal: index file corrupt

이 오류를 해결하려면을 (으) sed로 교체하여 를 되돌려 야 new_string합니다 old_string. 교체 된 문자열을 되돌 리므로 문제의 시작 부분으로 돌아갑니다.

문자열을 검색하고 바꾸는 올바른 방법 은 이진 파일을 무시하기 위해 건너 뛰고 대신 find사용하는 grep것입니다.

sed -ri -e "s/old_string/new_string/g" $(grep -Elr --binary-files=without-match "old_string" "/files_dir")

@hobs의 크레딧


1

여기 내가 할 일이 있습니다 :

find /path/to/dir -type f -iname "*filename*" -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

이 포함 된 모든 파일을 찾을 것입니다 filename세 이하 파일의 이름 /path/to/dir이있는 행을 검색, 발견 된 모든 파일에 대한보다 searchstring및 교체 old와 함께 new.

filename파일 이름에 문자열이 있는 특정 파일을 찾는 것을 생략하려면 다음과 같이하십시오.

find /path/to/dir -type f -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

이것은 위와 동일한 작업을 수행하지만 아래에있는 모든 파일에 적용됩니다 /path/to/dir.


0

또 다른 옵션은 globstar와 함께 perl을 사용하는 것입니다.

사용 shopt -s globstar당신에 .bashrc(어디든지)가 허용 **글로브 패턴이 반복적으로 모든 하위 디렉토리와 파일을 일치.

따라서를 perl -pXe 's/SEARCH/REPLACE/g' -i **재귀 적으로로 대체 SEARCH합니다 REPLACE.

-X플래그는 perl에게 "모든 경고를 비활성화"하도록 지시합니다. 즉, 디렉토리에 대해 불평하지 않습니다.

또한 globstar를 사용하면 확장자 가 있는 모든 하위 파일에서 sed -i 's/SEARCH/REPLACE/g' **/*.ext바꾸려는 경우 와 같은 작업을 수행 할 수 있습니다 .SEARCHREPLACE.ext


"또 다른 옵션은 globstar와 함께 perl을 사용하는 것입니다 ..." -Solaris와 같은 Posixy 시스템에는 없습니다. 그게 내가 특별히 찾고 있어요 이유 grepsed.
jww
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.