재귀 디렉터리에서 빠른 문자열 교체

재귀 디렉터리에서 빠른 문자열 교체

어떻게 하나 만들 수 있어?빠르게텍스트바꾸다그리고재귀적디렉터리 및 파일 이름공간그리고아포스트로피? 표준 UNIX 도구나 잘 알려진 소프트웨어 패키지를 사용하는 것이 가장 좋습니다.

이를 사용하면 각 파일에 대해 새로운 프로세스가 생성되므로 많은 파일에서 매우 느립니다 find. 따라서 디렉터리 순회와 문자열 교체를 하나의 작업으로 통합하는 방법을 찾고 있습니다.

느린 검색:

find . -name '*.txt'  -exec grep foo {} \;

빠른 검색:

grep -lr --include=*.txt foo

느린 교체:

find . -name '*.txt' -exec perl -i -pe 's/foo/bar/' {} \;

빠른 교체:

# Your suggestion here

(이것은 매우 빠르지만 두 번의 패스가 필요하고 공백을 처리하지 않습니다.)

perl -p -i -e 's/foo/bar/g' `grep -lr --include=*.txt foo`

답변1

당신은 단지 다음을 사용하고 싶습니다 :

 find . -name '*.txt'  -exec cmd {} \;

cmd하나의 인수만 허용하는 s 형식입니다. 그렇지 않다 grep. 그리고 grep:

 find . -name '*.txt'  -exec grep foo /dev/null {} +

(또는 -HGNU와 함께 사용됨 grep). 자세한 내용은 다음을 방문하세요.재귀 grep과 find / -type f -exec grep {} \; 중 어느 것이 더 효율적이고 빠르나요?

이제 교체를 위해 이는 동일하며 perl -pi여러 인수를 사용합니다.

 find . -name '*.txt' -type f -exec perl -pi -e s/foo/bar/g {} +

이제 이러한 파일은 포함 여부에 관계없이 덮어쓰게 됩니다 foo. 대신 다음을 원할 것입니다(GNU grepxargs/또는 호환성 가정).

 find . -name '*.txt' -type f -exec grep -l --null foo {} + |
   xargs -r0 perl -pi -e s/foo/bar/g

또는:

 grep -lr --null --include='*.txt' foo . |
   xargs -r0 perl -pi -e s/foo/bar/g

따라서 포함된 파일만 foo다시 작성됩니다.


BTW --include=*.txt( --include또 다른 GNU 확장)는 쉘 글로브이므로 인용해야 합니다. 예를 들어 --include=foo.txt호출 중인 현재 디렉터리에 파일이 있는 경우 셸은 를 --include=*.txt호출하기 전에 해당 파일로 확장 됩니다 grep. 그렇지 않은 경우 많은 쉘에서 glob이 어떤 파일과도 일치하지 않는다는 오류가 발생합니다.

그래서 당신은 원할 것입니다grep --include='*.txt'

답변2

표현식이 이렇게 간단 하면 find쉘을 사용하여 와일드카드를 사용할 수 있습니다. 발생할 수 있는 주요 제한 사항은 명령줄에서 수용할 수 있는 것보다 더 많은 파일을 처리하는 것입니다.

Bash의 예:

$ shopt -s globstar

$ date > a.txt
$ date > b.txt
$ date > c.txt
$ cat *.txt
Thu Mar 29 14:57:57 EDT 2018
Thu Mar 29 14:58:00 EDT 2018
Thu Mar 29 14:58:02 EDT 2018
$ mkdir -p deep/sub/dir
$ mv *.txt deep/sub/dir

$ perl -pi -e 's/EDT/EST/' **/*.txt

$ cat deep/sub/dir/*.txt
Thu Mar 29 14:57:57 EST 2018
Thu Mar 29 14:58:00 EST 2018
Thu Mar 29 14:58:02 EST 2018

답변3

find ... -exec";" 대신 "+" 종결자를 사용하여 파일을 한 번에 하나씩 실행하는 대신 일괄적으로 실행할 수 있습니다 ( exec실행 중인 명령이 한 번에 여러 파일 호출을 지원하는 경우).

find . -name '*.txt' -exec grep foo {} +
find . -name '*.txt' -exec perl -i -pe 's/foo/bar/' {} +

관련 정보