我必须用另一个文本块替换文件中的一大块文本(shell 脚本代码)。
我印象深刻的是如何使用 sed 替换多行字符串?回答者 安塔克和多行替换回答者布鲁斯·艾迪格
但我在使用它们时遇到了一些麻烦。
安塔克在他的回答中已经提到,
1h;2,$H;$!d;g;
对于大文件,不建议将整个文件()流式传输到缓冲区,因为它会使内存过载。我知道
sed
可以与块功能一起使用来保留块外的文本不变。我想使用这个功能。但如果我使用,sed -i '/marker1/,/marker2/s/.*/new text (code)/' filename
它将为每个流重复插入新文本(代码)。因此,我必须使用类似于建议的内容将视觉块作为一个流安塔克较早,但针对的是块(不是整个文件)。
正如所提到的布鲁斯·艾迪格可以尝试以点开头
ex
的附加功能,但我的新文本(代码)包含以点开头的行,这可以被视为附加语法的点。在这种情况下我该如何使用它?a
.
ex
的dd
“行数”可能会删除多行,但是如果我在 /marker1/ 和 /marker2/ 之间有一个块,其行数不固定(变化)要替换为新文本(代码),该怎么办它 ?
答案1
我建议使用Change 命令(本质上是一个delete 加上Apend,尽管追加仅应用于范围中的最后一行,这正是您想要的):
sed -i '/marker1/,/marker2/c\
New text 1\
New text 2' filename
这里使用 GNUsed
的语法进行就地编辑 ( -i
)。该c
命令在其他方面是标准且可移植的。 GNUsed
支持:
sed '/marker1/,/marker2/cNew text 1\
New text 2' filename
作为非标准扩展。
替换文本中必须对换行符和反斜杠字符进行转义(使用反斜杠)。
答案2
使用 GNU sed
要替换从匹配行开始3
并继续到匹配行的5
行New Code
:
$ seq 8 | sed '/3/,/5/{/5/ s/.*/New Code/; t; d}'
1
2
New Code
6
7
8
对于 range 中的行/3/,/5/
,我们测试该行是否匹配5
(意味着这是组中的最后一行),如果是,我们进行替换以 insert New Code
。如果进行了替换,则该t
命令告诉 sed 跳转到命令的末尾(在这种情况下New Code
会打印出来)。如果没有,该d
命令告诉 sed 删除该行。
所有其他行均正常打印。
要就地更改文件,-i
可以使用以下选项:
sed -i.bak '/3/,/5/{/5/ s/.*/New Code/; t; d}' file
使用 awk
使用 awk 执行相同操作:
$ seq 8 | awk '/3/,/5/{if (!f)print "New Code"; f=1; next}; 1'
1
2
New Code
6
7
8
awk 命令特别对待范围内的行/3/,/5/
。对于该范围内的行,我们测试是否f
为零(即,如果!f
为真),如果是,则打印New Code
并设置f
为 1,然后跳过其余命令并跳转到该next
行。
对于范围之外的行/3/,/5/
,不会进行跳转并1
导致打印该行。更详细地说,1
是一个条件。由于1
不为零,因此条件计算结果为 true。由于没有与条件关联的操作,因此执行默认操作,即打印该行。这1
是 print-the-line 的简写。
要就地更改文件,该-i inplace
选项可以与 GNU awk
4.1 或更高版本一起使用:
awk -i inplace '/3/,/5/{if (!f)print "New Code"; f=1; next} 1' file
答案3
基于上面的讨论我想出了一个解决方案ex
seq 15 > test1.txt
ex test1.txt << EOEX
/^7/,/^9/c
abcd
123
.xyz
hfr4
.
w!
q
EOEX
cat test1.txt
上面给出
1
2
3
4
5
6
abcd
123
.xyz
hfr4
10
11
12
13
14
15
谢谢g男让我了解更改命令并对点进行澄清。sed
和都ex
共享几乎相似的更改命令语法(也适用于删除命令、追加命令等)。