대규모 폴더 계층 구조에서 텍스트를 바꾸는 방법은 무엇입니까?

대규모 폴더 계층 구조에서 텍스트를 바꾸는 방법은 무엇입니까?

다수의 파일에서 특정 텍스트(특정 인스턴스 제외)를 검색하고 바꾸고 싶습니다. 각 행에 대해 해당 행을 교체해야 하는지 묻는 메시지가 표시되기를 원합니다. vim과 비슷 하지만 :%s/from/to/gc( c확인 메시지 포함) 폴더 집합에 걸쳐 있습니다. 사용할 수 있는 좋은 명령줄 도구나 스크립트가 있습니까?

답변1

왜 vim을 사용하지 않습니까?

vim은 모든 파일을 엽니 다

vim $(find . -type f)

아니면 관련 파일을 엽니다(Caleb이 제안한 대로).

vim $(grep 'from' . -Rl)

그런 다음 모든 버퍼에서 교체를 실행합니다.

:bufdo %s/from/to/gc | update

sed를 사용하여 이 작업을 수행할 수도 있지만 sed내 sed 지식은 제한되어 있습니다.

답변2

-l -pe인수로 전달된 파일( )을 한 줄씩( ) 교체하도록 지시하는 작은 Perl 스크립트를 사용하여 간단한 작업을 수행할 수 있습니다 -i.

perl -i -l -pe '
    if (/from/) {                            # is the source text present on this line?
        printf STDERR ("%s: %s [y/N]? ", $ARGV, $_);  # display a prompt
        $r=<STDIN>;                                   # read user response
        if ($r =~ /^[Yy]/) {                          # if user entered Y:
            s/from/to/g;                              # replace all occurences on this line
    }' /path/to/files

가능한 개선 방법은 프롬프트 섹션에 색상을 지정하고 "현재 파일의 모든 이벤트 교체"와 같은 기능을 지원하는 것입니다. 각 이벤트를 연속적으로 개별적으로 표시하는 것이 더 어려울 수 있습니다.

두 번째 부분은 파일 일치입니다. 관련된 파일이 너무 많지 않고 zsh를 실행 중인 경우 현재 디렉터리와 하위 디렉터리의 모든 파일을 재귀적으로 일치시킬 수 있습니다.

perl -i -l -pe '…' **/*(.)

쉘이 bash ≥4이면 실행할 수 있지만 perl … **/*sed가 디렉토리에서 실행을 시도하고 실패하기 때문에 가짜 오류 메시지가 생성됩니다. 파일 집합(예: C 파일) 내에서만 교체를 수행하려는 경우 일치를 제한할 수 있습니다(bash ≥4 또는 zsh에서 작동).

perl -i -l -pe '…' **/*.[hc]

대체되는 파일에 대해 더 많은 제어가 필요한 경우, 쉘에 재귀적 디렉토리 일치 구성이 없는 경우 , 파일이 너무 많아 "명령줄이 너무 깁니다" 오류가 발생하는 경우에 **사용하십시오 find. 예를 들어, 이름이 지정된 모든 파일 *.h이나 현재 디렉터리 및 그 하위 디렉터리 에서 교체를 수행하려면 (이전 시스템에서는 줄 끝에서 대신 *.c사용해야 할 수도 있습니다 (이 형식이 더 빠르지만 모든 곳에서 사용할 수 있는 것은 아닙니다).\;++

find . -type f -name '*.[hc]' -exec perl -i -l -pe '…' {} +

그렇긴 하지만, 상호작용이 필요하다면 저는 대화형 편집기를 사용하겠습니다.Gert가 Vim에서 이를 수행하는 방법을 보여줍니다., 검색하려는 모든 파일을 열어야 하지만 파일이 많으면 문제가 될 수 있습니다.

Emacs에서는 다음과 같이 할 수 있습니다:

  1. M-x find-name-dired(최상위 디렉터리 지정) 또는 M-x find-dired(명령줄 지정)을 사용하여 파일 이름을 수집합니다 find.
  2. 결과적으로피곤하다버퍼링하고 t모든 파일 표시를 누른 다음Q( dired-do-query-replace-regexp)표시된 파일을 신속하게 교체합니다.

답변3

sdiff(바라보다http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiff) 여기서 유용할 수 있습니다. 이를 통해 대화형으로 작업할 수 있습니다. 따라서 이를 수행하기 위해 교체 작업을 수행하여 생성된 임시 파일을 사용하는 것이 sed가능한 해결책일 수 있습니다.

# use file descriptor 3 to still allow use of stdin
while IFS= read -r -d '' file <&3; do

  # write the result of the replacement into a temporary file
  sed -r 's/something/something_else/g' -- "$file" > replacer_tmp

  if cmp -s -- "$file" replacer_tmp; then
    continue; # nothing was replaced
  fi

  echo "There is something to replace in '$file'! Starting interactive diff."
  echo

  sdiff -o "$file" -s -d -- "$file" replacer_tmp

  echo

done 3< <(find . -type f -print0)

(POSIX가 아닌 프로세스로 대체되고 read -d지원되는 파일 루프를 사용하십시오 bash.)

관련 정보