使用sed搜索并替换多行模式

时间:2016-06-19 00:20:47

标签: bash sed

我已经看到很多关于这个问题的例子,但还没有看到为我量身定制的那个。虽然我对sed非常熟悉,但是当谈到更高级的功能时,我很惭愧地说我是个菜鸟。这是手头的问题。

我有一个多线模式,我可以成功地与sed匹配,

sed -e '/Favorite Animals/, /!/p

Favorite Animals
Monkey
Penguin
Cat
!
Favorite Things
Shoe
Dog
Wheel
Moth
!

我个人喜欢这个表达式的是我可以将可变数量的行匹配到感叹号。现在让我们说我想进行搜索并替换相同的模式。基本上我想用我选择的任何字符串替换之前演示过的多行模式。有任何想法吗?我希望与我演示的sed命令有类似的语法,但乞丐不能选择。

我的想法是,我可以用字符串替换感叹号分隔的其中一个组。我称之为“条目”。我希望能够更新或覆盖这些条目。如果我有一个最喜欢的动物的更新版本,我希望能够用这样的新条目替换旧条目。

Favorite Animals
Sloth
Platypus  
Badger
Dog
!
Favorite Things
Shoe
Dog
Wheel
Moth
!

正如你所看到的,我现在不再是猴子的粉丝了。

2 个答案:

答案 0 :(得分:4)

有多种选择 - ica命令都可以使用。

修正后的答案

此修订后的答案涉及问题中现在修改的数据文件。这是修改后的data文件的温和增强版本:

There's material at the start of the file then the key information:
Favourite Animals
Monkey
Penguin
Cat
!
Favourite Things
Shoe
Wheel
Moth
!
and some material at the end of the file too.

这三个sed脚本中的所有三个都产生相同的输出:

sed '/Favourite Animals/,/!/c\
Favourite Animals\
Sloth\
Platypus\
Badger\
!
' data

sed '/Favourite Animals/i\
Favourite Animals\
Sloth\
Platypus\
Badger\
!
/Favourite Animals/,/!/d' data

sed '/Favourite Animals/a\
Favourite Animals\
Sloth\
Platypus\
Badger\
!
/Favourite Animals/,/!/d' data

示例输出:

There's material at the start of the file then the key information:
Favourite Animals
Sloth
Platypus
Badger
!
Favourite Things
Shoe
Wheel
Moth
!
and some material at the end of the file too.

脚本全部使用唯一字符串/Favourite Animals/并且不关闭重复的尾随上下文/!/,这一点至关重要。如果ia使用/!/而不是/Favourite Animals/,则输出会发生变化 - 而不是更好。

/!/i

There's material at the start of the file then the key information:
Favourite Animals
Sloth
Platypus
Badger
!
Favorite Things
Shoe
Wheel
Moth
Favourite Animals
Sloth
Platypus
Badger
!
!
and some material at the end of the file too.

/!/a

There's material at the start of the file then the key information:
Favourite Animals
Sloth
Platypus
Badger
!
Favorite Things
Shoe
Wheel
Moth
!
Favourite Animals
Sloth
Platypus
Badger
!
and some material at the end of the file too.

额外请求

  

是否可以使用sed选择范围内的范围?基本上,如果我想在之前指定的范围内更改或删除一个/多个我最喜欢的动物,该怎么办?那是/Favorite Animals/,/!/...在这个范围内改变的东西。

是的,当然。对于单个映射:

 sed '/Favourite Animals/,/!/ s/Monkey/Gorilla/'

对于多个映射:

 sed '/Favourite Animals/,/!/ {
      s/Monkey/Gorilla/
      s/Penguin/Zebra/
      s/Cat/Dog/
      }'

如果您愿意,也可以将它们组合成一行 - 使用分号分隔它们:

 sed '/Favourite Animals/,/!/ { s/Monkey/Gorilla/; s/Penguin/Zebra/; s/Cat/Dog/; }'

请注意,GNU sed和BSD(Mac OS X)sed对最后一个分号的必要性有不同的看法 - 显示的内容对两者都有效。

原始答案适用于更简单的输入文件。

原始答案

考虑包含以下内容的文件data

There's material
at the start of the file
then the key information:
Favourite Animals
Monkey
Penguin
Cat
!
and material at the end of the file too.

使用c,您可以写:

$ sed '/Favourite Animals/,/!/c\
> Replacement material\
> for the favourite animals
> ' data
There's material
at the start of the file
then the key information:
Replacement material
for the favourite animals
and material at the end of the file too.
$

使用i,您可以使用:

$ sed '/Favourite Animals/i\
> Replacement material\
> for the favourite animals
> /Favourite Animals/,/!/d' data
There's material
at the start of the file
then the key information:
Replacement material
for the favourite animals
and material at the end of the file too.
$

使用a,您可以写:

$ sed '/!/a\
> Replacement material\
> for the favourite animals
> /Favourite Animals/,/!/d' data
There's material
at the start of the file
then the key information:
Replacement material
for the favourite animals
and material at the end of the file too.
$

请注意:

  • c - 您更改了整个范围
  • i - 在删除整个范围之前插入范围中的第一个模式
  • a - 在删除整个范围之前追加范围中的最后一个模式

但是,考虑到它,您可以在删除整个范围之前插入范围中的最后一个模式之前,或者在删除整个范围之前追加范围中的第一个模式之后。因此,ia的键是在基于范围的删除之前放置“替换文本”操作。但c最简洁。

答案 1 :(得分:1)

i(插入)命令具有难看的语法,但它可以工作:

sed '/Favorite Animals/i\
some new text\
some more new text\
and a little more
/Favorite Animals/,/!/d'