使用 sed 删除所有以模式 b 开头的行,然后是模式 a 的行

Posted

技术标签:

【中文标题】使用 sed 删除所有以模式 b 开头的行,然后是模式 a 的行【英文标题】:Use sed to delete all lines starting with pattern b after line with pattern a 【发布时间】:2021-01-08 01:23:13 【问题描述】:

给定一个类似的文件:

first line
second line DELETE ME
  - third line
  - fourth line
fifth line
sixth line DELETE ME
seventh line
  - eighth line

还有模式 a (DELETE ME) 和模式 b ([[:blank:]]*-),我只想保留

first line
fifth line
seventh line
  - eighth line

或者换句话说,我想删除包含模式 a 的每一行以及所有以模式 b 开头的直接跟随行>.

到目前为止,我只满足了部分但不是全部要求:

sed '/DELETE ME/N;s/^[[:blank:]]*-//;d;'

这应该删除所有包含 a 的行以及包含 b 的连续行。

【问题讨论】:

您是否致力于 sed,或者其他工具是否可以接受? 这是一个 yaml 文件吗? sed '/DELETE ME/:a;N;s/\n[[:blank:]]*-.*//;ta;!P;D' file 我的最终目标是:我有一个 gitlab-ci 模板存储库,其中包含许多 gitlab-ci yaml 文件,使用(可能嵌套)包含。现在我想为该存储库创建一个 gitlab-ci 文件,根据included CI lint tool(API)检查包含的所有文件的有效性。我发现this solution 用于稍微不那么通用的情况,但想使其适应我的用例. --- @WiktorStribiżew 似乎可行,您介意添加解释并提交作为答案吗? 【参考方案1】:

使用 GNU sed,您可以使用

sed '/DELETE ME/:a;N;s/\n[[:blank:]]*-.*//;ta;!P;D' file

见online sed demo:

s='first line
second line DELETE ME
  - third line
  - fourth line
fifth line
sixth line DELETE ME
seventh line
  - eighth line'
sed '/DELETE ME/:a;N;s/\n[[:blank:]]*-.*//;ta;!P;D' <<< "$s"

输出:

first line
fifth line
seventh line
  - eighth line

详情

/DELETE ME/ - 查找所有包含 DELETE ME 字符串的行 :a;N;s/\n[[:blank:]]*-.*//;ta;!P;D - 如果找到匹配 DELETE ME 的行,则进入此块: :a - a 标签标记当前位置 N - 将带有 \n 开头的下一行读入模式空间 s/\n[[:blank:]]*-.*// - 查找并删除换行符、0+ 个空白字符、- 和字符串的其余部分 ta - 如果发生替换,sed 会转到标有 a 的位置 !P - 否则,打印模式空间内容直到第一个换行符(即打印第一行) D - 删除模式空间内容直到第一个新行,即删除模式空间内的第一行,并使用生成的模式空间重新开始循环,而不读取新的输入行。

【讨论】:

【参考方案2】:

虽然 yaml 文件应该由理解它们的工具解析,但由于 OP 使用了sed,所以我在这里提出了awk 解决方案。请您尝试以下操作。在链接https://ideone.com/WNROOt 中编写和测试,并且仅使用显示的示例进行测试和编写。

awk '
!/^ +/
  foundDel=""

/DELETE ME/
  foundDel=1
  next

foundDel && /^ +/
  next

1
' Input_file

注意:如果您想将输出保存到 Input_file 本身,请附加 &gt; temp &amp;&amp; mv temp Input_file

【讨论】:

【参考方案3】:

这可能对你有用(GNU sed):

sed -n '/DELETE ME/:a;n;/^\s*-/ba;p' file

通过设置选项-n关闭隐式打印。

遇到包含DELETE ME 的行时,形成一个循环以获取下一行,如果该行以一些空格开头,后跟-,则重复循环。

否则,打印所有其他行。

【讨论】:

这会在我的设置中产生sed: unterminated 试试'/DELETE ME/:a;n;/^\s*-/ba;;p'

以上是关于使用 sed 删除所有以模式 b 开头的行,然后是模式 a 的行的主要内容,如果未能解决你的问题,请参考以下文章

文本处理工具sed

自建yum仓库;编译安装http2.4 ;删除/etc/fstab文件中所有以#开头的行;sed 取本机的IP地址;sed命令取目录名

Linux练习题-文本处理工具sed(施工中)

删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符

关于find与sed命令的几个使用

shell中修改文件内容