用数学术语表达,我想删除 的一个区域[MarkA,MarkB)
。即,删除发生在MarkA
遇到关键字时,一直到关键字MarkB
,但不包括该行(包含关键字的行 MarkB
保持不变)。
有可能这样做吗sed
?
说我的MarkA
是^3
,MarkB
是7
,
$ 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。
一个数字将指定的行数添加到地址。