세 번째 파일에서 out.txt의 내용을 in.txt로 바꾸는 방법은 무엇입니까?

세 번째 파일에서 out.txt의 내용을 in.txt로 바꾸는 방법은 무엇입니까?

main.txt, out.txt의 세 개의 파일이 있습니다 . in in.txt의 모든 내용을 의 내용으로 바꾸고 싶습니다 .out.txtmain.txtin.txt

out.txt및 둘 다 in.txt여러 줄과 다양한 특수 문자를 포함할 수 있습니다. 이 문자열을 올바르게 읽고 이스케이프하려면 어떻게 해야 합니까?

이는 특수 문자, 중복 일치, 불완전 일치, 중복 일치와 같은 일부 극단적인 경우의 예입니다.

main.txt:

foo
Replace these
three lines
with some $.*\'"& in it
bar
Replace these
three lines
with some $.*\'"& in it
Replace these
three lines
with some $.*\'"& in it

three lines
Replace these
three lines
three lines
with some $.*\'"& in it
baz

out.txt:

Replace these
three lines
with some $.*\'"& in it

in.txt:

Replacement lines
also with $.*\'"&

예상 출력:

foo
Replacement lines
also with $.*\'"&
bar
Replacement lines
also with $.*\'"&
Replacement lines
also with $.*\'"&

three lines
Replace these
three lines
three lines
with some $.*\'"& in it
baz

답변1

그리고 perl:

perl -0777 -e '$out = <>; $in = <>; $_ = <>; s/\Q$out\E/$in/g; print
              ' out.txt in.txt main.txt > new-main.txt

메모리에 들어갈 만큼 작은 한, 파일에 포함될 수 있는 모든 문자 또는 비문자에 대해 작동해야 합니다(바이너리 파일에도 작동함).

-0777입력 레코드 구분 기호를 불가능한 값으로 설정하여 실행과 동일하게 $/ = undef하여 <>인자로 전달된 파일부터 순차적으로 전체 파일을 읽습니다.

따라서 // ​​전체 내용 이 , 및 , $out각각 있습니다 .$in$_out.txtin.txtmain.txt

$_s/pattern/replacement/flagsprint기본적 으로 연산자에 의해 처리되는 변수입니다 .패턴 공간존재하다 sed.

여기서 패턴은 내부 콘텐츠가 정규 표현식이 아닌 문자 그대로 처리되도록 하는 것입니다 \Q$out\E. \Q...\Eg플래그는 에서와 같이 발생하는 모든 상황을 대체합니다 sed.


또는 명령 출력(예 ls|: <<>>파일 경로로만 해석되는 명령 출력)을 대신 사용하십시오.

답변2

모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.

$ cat tst.awk
FILENAME == ARGV[1] { old = old $0 ORS }
FILENAME == ARGV[2] { new = new $0 ORS }
FILENAME == ARGV[3] { rec = rec $0 ORS }
END {
    lgth = length(old)
    if ( lgth > 0 ) {
        while ( beg = index(rec,old) ) {
            printf "%s%s", substr(rec,1,beg-1), new
            rec = substr(rec,beg+lgth)
        }
    }
    printf "%s", rec
}

$ awk -f tst.awk out.txt in.txt main.txt
foo
Replacement lines
also with $.*\'"&
bar
Replacement lines
also with $.*\'"&
Replacement lines
also with $.*\'"&

three lines
Replace these
three lines
three lines
with some $.*\'"& in it
baz

위의 내용은 리터럴 문자열 일치 및 바꾸기를 수행하므로 입력 파일의 모든 문자에 대해 작동합니다.

답변3

쉘이 이를 지원하는 경우 <()(예 zsh: , , ksh, bash) 파일 사이에 마커를 삽입하여(여기: MARK) 파일을 구분하고 POSIX를 사용할 수 있습니다 sed.

sed -e 'H;1h;$!d;x;:L
        s/^\(.*\)\(MARK\n\)\(.*\)\2\(.*\)\1/\1\2\3\2\4\3/;tL
        s/.*MARK\n//' out.txt <(echo MARK) in.txt <(echo MARK) main.txt
  • H;1h;$!d;x전체 파일을 한번에 처리하는 일반적인 모드입니다
  • :L주기를 시작하다
  • s/^\(.*\)\(MARK\n\)\(.*\)\2\(.*\)\1/\1\2\3\2\4\3/out.txt다음 으로 교체in.txt
  • tL교체할 수 있으면 재활용할 수 있습니다.
  • s/.*MARK\n//인쇄하기 전에 다른 파일을 삭제하세요.

제한사항에 유의하세요.

  1. MARK당연히 텍스트의 일부가 아닌 섹션을 선택해야 합니다 .
  2. 설명했듯이 구현에 따라 대용량 파일의 경우 실패할 수 있습니다 sed. 나는 현대 시스템에서 이 경계에 부딪힌 적이 없지만 존재합니다. 일치하지 않는 행을 새로 고치면 문제가 해결되지만 이는 처음부터 프로그래밍일 뿐 목적은 아닙니다 sed.

관련 정보