每次用不同的字符串替换模式(取自外部文件)

每次用不同的字符串替换模式(取自外部文件)

我有一个输入:

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,假设TOCHANGE不会出现在externalfile(或者更一般地说,替换不会生成新的出现,例如在包含和的TOCHANGE输入上也可能发生):TOTOCHANGE 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上面被视为扩展正则表达式。如果您希望按照字面意思处理 ERE 运算符(例如PAT='TO\.CHANGE'替换TO.CHANGE字符串),您可能需要转义 ERE 运算符。

答案2

这可以使用 GNU sed 来完成,如下所示:

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

在第一遍中,sed将在 input.txt 中的所有行的 TOCHANGE 行下方放置一行 file_2

在下一遍中,包含 TOCHANGE 的行将与以下行连接在一起,并且 as/// 替换将获得预期的输出。

珀尔它可以实现为:

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

答案3

有了这个 awk

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

相关内容