我必须用另一个文本块替换文件中的一大块文本(shell 脚本代码)。
我对如何使用 sed 替换多行字符串印象深刻?由antak回答 ,多线替换由Bruce Ediger回答
但是我在使用它们时遇到了一些麻烦。
antak在他的回答中已经提到,1h;2,$H;$!d;g;
对于大文件,不建议将整个文件 ( )流式传输到缓冲区,因为它会导致内存过载。
我知道sed
可以与块功能一起使用以保持块外的文本不变。我想使用这个功能。但如果我使用,
sed -i '/marker1/,/marker2/s/.*/new text (code)/' filename
Run Code Online (Sandbox Code Playgroud)它将为每个流重复插入新文本(代码)。因此,我必须将可视块作为一个流,使用类似于antak之前建议的内容,但用于块(不是用于整个文件)。
正如Bruce Ediger提到的,可以尝试以(点)ex
开头的附加功能,但我的新文本(代码)包含以点开头的行,这可能被认为是附加语法的点。在这种情况下我该如何使用它?a
.
ex
's dd
'number of lines' 可能会删除多行,但是如果我在 /marker1/ 和 /marker2/ 之间有一个块,其中的行数不固定(变化)将被替换为新文本(代码),该怎么办它 ?
G-M*_*ca' 14
我建议使用c hange 命令(它本质上是一个d elete 加上一个ppend,尽管 append 仅应用于范围中的最后一行,这正是您在这里想要的):
sed -i '/marker1/,/marker2/c\
New text 1\
New text 2' filename
Run Code Online (Sandbox Code Playgroud)
这里使用 GNUsed
的语法进行就地编辑 ( -i
)。该c
命令在其他方面是标准且可移植的。GNUsed
支持:
sed '/marker1/,/marker2/cNew text 1\
New text 2' filename
Run Code Online (Sandbox Code Playgroud)
作为非标准扩展。
必须在替换文本中对换行符和反斜杠字符进行转义(使用反斜杠)。
要更换启动线匹配的行3
,并继续到线匹配5
具有New Code
:
$ seq 8 | sed '/3/,/5/{/5/ s/.*/New Code/; t; d}'
1
2
New Code
6
7
8
Run Code Online (Sandbox Code Playgroud)
对于 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
Run Code Online (Sandbox Code Playgroud)
使用 awk 做同样的事情:
$ seq 8 | awk '/3/,/5/{if (!f)print "New Code"; f=1; next}; 1'
1
2
New Code
6
7
8
Run Code Online (Sandbox Code Playgroud)
awk 命令/3/,/5/
专门处理范围内的行。对于该范围内的行,我们测试是否f
为零(即,如果!f
为真),如果是,则打印New Code
并设置f
为 1,然后跳过其余命令并跳转到该next
行。
对于 range 之外的行/3/,/5/
,不进行跳转并1
导致打印该行。更详细地说,1
是一个条件。因为1
不为零,条件评估为真。因为没有与条件相关联的操作,所以执行默认操作,即打印该行。因此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
Run Code Online (Sandbox Code Playgroud)