main.txt
, out.txt
의 세 개의 파일이 있습니다 . in in.txt
의 모든 내용을 의 내용으로 바꾸고 싶습니다 .out.txt
main.txt
in.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.txt
in.txt
main.txt
$_
s/pattern/replacement/flags
print
기본적 으로 연산자에 의해 처리되는 변수입니다 .패턴 공간존재하다 sed
.
여기서 패턴은 내부 콘텐츠가 정규 표현식이 아닌 문자 그대로 처리되도록 하는 것입니다 \Q$out\E
. \Q...\E
이 g
플래그는 에서와 같이 발생하는 모든 상황을 대체합니다 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//
인쇄하기 전에 다른 파일을 삭제하세요.
제한사항에 유의하세요.
MARK
당연히 텍스트의 일부가 아닌 섹션을 선택해야 합니다 .- 설명했듯이 구현에 따라 대용량 파일의 경우 실패할 수 있습니다
sed
. 나는 현대 시스템에서 이 경계에 부딪힌 적이 없지만 존재합니다. 일치하지 않는 행을 새로 고치면 문제가 해결되지만 이는 처음부터 프로그래밍일 뿐 목적은 아닙니다sed
.