명령 줄 : grep과 일치하는 모든 파일 이름에서 검색 및 바꾸기


80

grep과 일치하는 모든 파일에서 문자열을 검색하고 바꾸려고합니다.

grep -n 'foo' * 다음과 같은 형식으로 출력을 제공합니다.

[filename]:[line number]:[text]

그렙에 의해 반환 된 각 파일에 대해, 나는 대체하여 파일을 수정하고 싶습니다 foo와 함께 bar.

답변:


70

grep과 일치하는 모든 파일에서 문자열을 검색하고 바꾸는 것을 의미합니까?

perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`

편집하다

이것은 상당히 인기있는 질문 인 것 같아서 업데이트 할 것이라고 생각했습니다.

요즘은 ack-grep사용자 친화적이기 때문에 주로 사용 합니다. 따라서 위의 명령은 다음과 같습니다.

perl -p -i -e 's/old/new/g' `ack -l searchpattern`

파일 이름의 공백을 처리하려면 다음을 실행할 수 있습니다.

ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

당신은 ack-grep. 검색을 HTML 파일로만 제한하려는 경우 :

ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

공백이 문제가되지 않는다면 더 짧습니다.

perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files

3
공백이 포함 된 파일 / 폴더에 문제가있을 수 있다고 생각합니다. Can't open Untitled: No such file or directory, <> line 5"Untitled Folder / file.txt"를 시도 할 때.
Xeoncross

108

당신이 준 예에 따르면 이것은 당신이 원하는 것 같습니다.

sed -i 's/foo/bar/g' *

재귀 적이 지 않습니다 (하위 디렉토리로 내려 가지 않음). 트리 전체에서 선택한 파일을 대체하는 멋진 솔루션을 위해 find를 사용합니다.

find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

(가) *.html파일이 일치해야하는 표현의 .bak애프터이 -i박 확장자를 가진 원본 파일의 사본을 만들어 (그것은 어떤 확장 당신처럼 될 수 있습니다)와 gsed의 식의 말은 여러 복사본을 대체하기 위해 sed를 알려줍니다 한 줄 (첫 번째 줄만 아님). -print찾을 파일이 일치되고 있었다 쇼에 편리합니다. 이 모든 것은 시스템에있는 이러한 도구의 정확한 버전에 따라 다릅니다.


1
cygwin 사용자를위한 경고의 한마디. find 및 sed 콤보는 스트리밍되는 파일에 대한 사용자 권한을 변경하는 것 같습니다. 이것은 find / sed가 작동 할 때 사용 된 것과 동일한 dir 레벨에서 chmod -R 644 * 명령을 사용하여 간단하게 수정할 수 있습니다.
kaskelotti

-i 인수를 사용하고 싶지 않은 사람들에 대한 경고 : -i 인수를 사용하지 않으면 작동하지 않습니다 (이유를 묻지 마십시오)
knocte

4
@knocte -i는 sed에게 파일을 수정하도록 지시하고, 그렇지 않으면 수정 된 버전을 stdout에 인쇄합니다. .bak 파일을 생성하지 않으려면 '.bak'부분을 생략하면됩니다. -i도 독립형으로 작동합니다.
MattJ 2013 년

2
OSX에서는 find시작할 디렉토리 (예 : find . -name '*.html'또는) 를 명령 에 제공해야합니다 find directoryname/ -name '*'.
Michiel Kauw-A-Tjoe

난 그렇지 않은 경우의 ... '부분은 접미사라고 생각하는 -e를 추가하는 데 필요한sed -ie 's/foo/bar/g' *
vish

14

옵션 sed(1)이 있으면 -i다음과 같이 사용하십시오.

for i in *; do
  sed -i 's/foo/bar/' $i
done

그렇지 않은 경우 사용하려는 언어에 따라 다음과 같은 여러 가지 방법이 있습니다.

ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *

2
for i in *; do ...sed는 파일 목록을 인수로 사용할 수 있습니다.
옌스

2
@Jens 위의 예제에 자신의 예제를 추가 하여이 답변을 개선하지 않으시겠습니까?
Magpie

변수는 항상 따옴표로 묶어야합니다for i in *; do; sed -i 's/foo/bar/g' "$i"; done
cat

6

위의 솔루션 또는 시스템 전체 검색을 좋아하고 사용했으며 수천 개의 파일 중에서 교체했습니다.

find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;

나는 '* .htm?'으로 가정한다. .html 대신 .htm 및 .html 파일을 모두 검색하고 찾습니다.

백업 파일을 더 쉽게 정리하기 위해 .bak를 시스템 전체에서 사용되는 물결표 (~)로 대체합니다.


4

이것은 perl을 사용하거나 찾을 필요없이 grep을 사용하여 작동합니다.

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @

xargs에는 OSX 또는 BSD에 -i가 없습니다. openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/… 대문자 "I"를 사용 하려고 했습니까?
Tony Adams

나는 -i다른 OS에서 작동 하지 않는다는 것을 몰랐습니다. 우분투에서 나를 위해 작동합니다.
pymarco 2014

xargs맨 페이지 (Ubuntu의) -i는 더 이상 사용되지 않으며 -I대신 사용 한다고 말합니다 . 그래서, 우리는 말해야한다 :grep -rli 'old-word' * | xargs -I filepath sed -i 's/old-word/new-word/g' filepath
최대 월러스

3

find . -type f -print0 | xargs -0 <sed/perl/ruby cmd>한 번에 하나의 인터프리터를로드하여 여러 공간에 포함 된 파일 이름을 처리합니다. 훨씬 더 빨리.


@knocte, "cmd"는 선택한 도구에 대한 전체 검색 및 바꾸기 명령에 대한 토큰입니다. 이 답변은 공백이 포함 된 파일 이름을 처리하는 방법에 대한 질문에 대한 답변입니다.
Tony Adams

1

이미 findsed 사용에 대한 대답

find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

아마도 표준 답일 것입니다. 또는 명령 perl -pi -e s/foo/bar/g'대신 사용할 수 있습니다 sed.

대부분의 빠른 사용을 위해 rpl 명령 이 기억하기 더 쉽다는 것을 알 수 있습니다. 다음은 현재 디렉토리의 모든 파일에서 재귀 적으로 대체 (foo-> bar)입니다.

rpl -R foo bar .

대부분의 Linux 배포판에서는 기본적으로 사용할 수 없지만 설치가 빠릅니다 ( apt-get install rpl또는 유사).

그러나 정규 표현식과 역 대체 또는 파일 이름 바꾸기와 검색 및 바꾸기를 포함하는 더 힘든 작업의 ​​경우 내가 아는 가장 일반적이고 강력한 도구는 repren입니다 . 까다로운 이름 변경 및 리팩토링 작업. 선호하는 이유는 다음과 같습니다.

  • 파일 이름 변경 및 파일 내용 검색 및 바꾸기 (디렉토리 간 파일 이동 및 새 상위 디렉토리 생성 포함)를 지원합니다.
  • 검색 및 바꾸기를 수행하기 전에 변경 사항을 확인하십시오.
  • 역 치환, 전체 단어, 대소 문자 구분 및 대소 문자 보존 (foo-> bar, Foo-> Bar, FOO-> BAR 대체) 모드로 정규 표현식을 지원합니다.
  • 스왑 (foo-> bar 및 bar-> foo) 또는 고유하지 않은 대체 세트 (foo-> bar, f-> x)를 포함한 여러 대체와 함께 작동합니다.

예제 는 README확인하십시오 .


1

이것은 실제로 보이는 것보다 쉽습니다.

grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
  • grep은 트리 (-R)를 반복하고 현재 디렉토리 (./)에서 시작하여 파일 이름 (-l) 만 인쇄합니다.
  • xargs로 파이프되어 한 번에 하나씩 처리되고 (-n 1) 쉘 명령 (sh -c)에서 자리 표시 자로 %를 사용합니다 (-I %).
  • 쉘 명령에서 먼저 파일 이름이 인쇄됩니다 (ls %;).
  • 그런 다음 sed는 인라인 연산 (-i), foo의 대체 ( 's /')를 bar (foo / bar)로, 전역 적으로 (/ g) 파일에서 (다시, %로 표시됨) 수행합니다.

쉬워요. find, grep, xargs, sed 및 awk에 대해 잘 알고 있다면 bash에서 텍스트 파일을 조작 할 때 거의 불가능한 것이 없습니다. :)


Bah, 무시하십시오.이 pymarco는 이미 위에서 이것을 다루었습니다. 설명을 위해 내 대답을 남겨주세요.
siliconrockstar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.