sed,删除从 MarkA 到 MarkB 但不包含 MarkB

sed,删除从 MarkA 到 MarkB 但不包含 MarkB

用数学术语表达,我想删除 的一个区域[MarkA,MarkB)。即,删除发生在MarkA遇到关键字时,一直到关键字MarkB,但不包括该行(包含关键字的行 MarkB保持不变)。

有可能这样做吗sed

说我的MarkA^3MarkB7

$ seq 9 | sed '/^3/,/7/d'
1
2
8
9

它将被7删除但我想保留它。

更准确地说,我可以准确定位MarkA(例如^3),但我想删除直到第一个MarkB。即,

seq 19 | sed '/^3/,/7/d'

7如果该行未被删除,我正在寻找什么。

答案1

使用 sed

这将删除直至但不包括最后一行的范围:

$ seq 9 | sed '/^3/,/7/{/7/p;d}'
1
2
7
8
9

与之前一样,/^3/,/7/选择整个范围,包括/7/。并且,与之前一样,该范围会通过命令删除d。但是,在删除之前,我们会检查该行是否包含/7/,如果包含,我们会通过命令将其打印出来p

使用 awk

awk 提供了很大的灵活性。在这里,我们使用一个变量f作为标志来决定是否应该打印行:

$ seq 9 | awk '/^3/{f=1} /7/{f=0} !f'
1
2
7
8
9

答案2

ed如果文件中有数据,则可以使用 sed 的前身:

seq 9 > data
printf '%s\n' '/^3/,/7/-1 d' 'wq' | ed -s data
cat data
1
2
7
8
9

该命令分解如下:

  • printf-- 向管道发送两个字符串;这两个字符串后面附加了一个换行符,因此它们看起来像命令ed。这两个命令是:
    • /^3/,/7/-1 d-- 在 /^3/ 到 /7/ 之前的范围内,删除以下行
    • wq-- 将文件写回磁盘并退出
  • ed -s data--ed以静默模式运行,这样它就不会报告最后写入的字节数。

这里最核心的有用功能是ed能够在范围正则表达式后使用加法或减法。(GNU)ed 手册页描述如下:

行地址的构造如下:

...

地址后面可以跟一个或多个地址偏移量,可选地用空格分隔。偏移量的构造如下:

'+' 或 '-' 后跟一个数字,会在地址中添加或减去指定的行数。

'+' 或 '-' 后面不跟数字,则会对地址加 1 或减 1。

一个数字将指定的行数添加到地址。

相关内容