我有一个输入:
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 FROMTOCHANGE
externalfile
CHANGE
WHATEVER
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=1
GNU 需要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