パターンを毎回別の文字列に置き換えます(外部ファイルから取得)

パターンを毎回別の文字列に置き換えます(外部ファイルから取得)

入力があります。

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

2番目の変形

"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

関連情報