패턴을 매번 다른 문자열로 교체(외부 파일에서 가져옴)

패턴을 매번 다른 문자열로 교체(외부 파일에서 가져옴)

입력이 있습니다.

a
b TOCHANGE
c
d 
e TOCHANGE

외부 파일을 사용하여 "TOCHANGE" 모드를 변경해야 합니다.

line1
line2
...

이렇게 하면 다음과 같은 결과를 얻습니다.

a
b line1    
c
d
e line2

다음 명령을 시도했습니다.

while read k ; do sed -i "s/TOCHANGE/$k/g" input ; done < externalfile

하지만 나는 다음을 얻습니다.

a
b line1    
c
d
e line1

답변1

그리고 perl:

perl -pi -e 's{TOCHANGE}{chomp ($repl = <STDIN>); $repl}ge' input <externalfile

의 경우 다음에서 발생이 발생하지 않는 awk것으로 가정됩니다 (또는 더 일반적으로 대체는 다음을 포함하는 입력에서 발생할 수 있는 것처럼 새 발생을 생성하지 않습니다 ).TOCHANGEexternalfileTOCHANGETOTOCHANGE FROMTOCHANGEexternalfileCHANGEWHATEVER

POSIXLY_CORRECT=1 PAT=TOCHANGE awk '
  {
    while ($0 ~ ENVIRON["PAT"]) {
      getline repl < "externalfile"
      gsub(/[&\\]/, "\\\\&", repl)
      sub(ENVIRON["PAT"], repl)
    }
    print
  }' < input > input.new

( POSIXLY_CORRECT=1GNU에서는 awk이를 요구합니다. 그렇지 않으면 백슬래시 문자가 포함된 문자열을 제대로 바꿀 수 없습니다.)

위의 내용은 $PAT확장 정규식으로 간주됩니다. 문자 그대로 처리하려면(예: 문자열 PAT='TO\.CHANGE'대체 ) ERE 연산자를 이스케이프해야 할 수도 있습니다.TO.CHANGE

답변2

이는 다음과 같이 GNU sed를 사용하여 수행할 수 있습니다.

sed -e '/TOCHANGE/R file_2' input.txt |
sed -e '/TOCHANGE/N;s/TOCHANGE\(.*\)\n\(.*\)/\2\1/' 

첫 번째 패스에서는sedfile_2 줄은 input.txt의 모든 줄에 대해 TOCHANGE 줄 아래에 배치됩니다.

다음 단계에서는 TOCHANGE가 포함된 줄이 다음 줄과 연결되고 as/// 대체를 통해 예상되는 출력이 제공됩니다.

그리고진주다음과 같이 구현할 수 있습니다.

perl -pe 's|TOCHANGE|<STDIN> =~ s/\n//r|e' input.txt < file_2

답변3

이걸로

awk -v old='TOCHANGE' '
NR==FNR{a[NR]=$0;next}
$2==old{$2=a[++i]}
1' changefile infile > outfile

답변4

까다로운 솔루션과 awk특정 기능을 결합하세요.

첫 번째 변종

"TOCHANGE"패턴이 각 행에서 한 번만 발생하는 경우 . 평소대로 awk면 충분합니다.

awk '{
    if(NF == 2) {
        getline OFS < "file_2"
        $1 = $1
    }    
    print
}' FS='TOCHANGE' input.txt

두 번째 변형

"TOCHANGE"패턴이 각 줄에 여러 번 나타날 수 있는 경우 . 필수의 gawk.

gawk '{
    RS="\n"
    if(RT)
        getline ORS < "file_2"
    else
        ORS=""

    print

    RS="TOCHANGE"
}' RS='TOCHANGE' input.txt

시험

입력.txt

a
b TOCHANGE
c
d 
e TOCHANGE
f
g TOCHANGE

파일_2

line1
line2
line3
line4

산출

a
b line1
c
d 
e line2
f
g line3

관련 정보