使用 sed 删除多行字符串的简单方法

Simple way to remove multi-line string using sed

使用 sed,有没有办法根据一些开始和结束表达式从文本文件中删除多行?

我知道文件中的标记并且想删除之间的所有内容(包括标记)。我见过一些非常复杂的解决方案,我想在不借助微命令的情况下做到这一点。

我的文件看起来像这样:

cat /tmp/foobar.txt
this is line 1

this is line 3

tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
annotations-api.jar,\
ant-junit*.jar,\
ant-launcher.jar,\
ant.jar,\
asm-*.jar,\
aspectj*.jar,\
bootstrap.jar,\
catalina-ant.jar,\
catalina-ha.jar,\
catalina-ssi.jar,\
catalina-storeconfig.jar

the end leave me
and me

我想删除从 tomcat.util 开始一直到最后 .jar

的所有内容

tldr;

我认为这是最简单的方法,不需要像微命令那样的汇编

sed '/^tomcat\.util.*$/,/^.*[^\]$/d' /tmp/foobar.txt

产生

this is line 1

this is line 3


the end leave me
and me

如果你想删除文件中的行而不是将输出输出到标准输出,那么使用 inline 标志,所以

sed -i '/^tomcat\.util.*$/,/^.*[^\]$/d' /tmp/foobar.txt

那么...这是如何工作的?

sed 命令,如 vi 命令在 address 上运行。通常我们不指定地址,而只是将命令应用于文件的所有行,例如,在文件中将 the 替换为 that 时,我们通常会执行

sed -i 's/the/that/g' /tmp/foobar.txt

即将替换或 s 命令应用于文件中的所有行。

在这种情况下,您想要删除 一些行,以便我们可以使用删除或d 命令。但是我们需要告诉它在哪里删除。所以我们需要给它一个地址。

sed命令的格式是

[addr][!]command[options]

(参见 the docs

如果未指定地址,则命令将应用于所有行,如果指定了 !,则将其应用于与模式不匹配的所有行。到目前为止一切顺利。

这里的技巧是 addr 可以是单个地址或地址范围。地址可以是行号或正则表达式模式。您在两个地址之间使用 , 来指定范围。

所以要删除第 5 行到第 8 行,您可以这样做

sed -i '5,8d' /tmp/foobar.txt

在这种情况下,我们知道一些“标记”而不是知道行号,我们可以改用 Regex,因此第一个标记,以 tomcat.util 开头的行由 regex

/^tomcat\.util.*$/

第二个标记有点棘手,但如果我们看一下,我们可以看到要删除的最后一行是第一个不以 \ 结尾的行,因此我们可以匹配包含以下内容的行的“任何但不以 \”结尾的

/^.*[^\]$/

虽然如果我们从这两个正则表达式中创建一个范围,第二个标记可以匹配一大堆行,但该范围意味着第二个“地址”是第一个匹配正则表达式的地址之后的第一行。

综上所述,我们要删除 (d) 正则表达式匹配以 tomcat.util 开头并以一行结尾的行找到的地址范围内的所有行不以 \ 结尾,即

sed '/^tomcat\.util.*$/,/^.*[^\]$/d' /tmp/foobar.txt

希望对您有所帮助 ;-)

干杯

卡尔

这可能适合您 (GNU sed):

sed -n '/tomcat\.util/{:a;n;/\.jar/ba};p' file

使用 -n 选项关闭隐式打印。

匹配包含 tomcat.util.

的行

继续获取行,直到这样的行与包含 .jar.

的行不匹配

打印所有其他行。


选择:

sed -E '/tomcat\.util/{:a;$!N;/\.jar(,\)?$/s/\n//;ta;D}' file

收集从 tomcat.util 开始到 .jar,\.jar 结束的行,删除换行符直到文件结尾或不匹配,然后删除集合。

Awk 通常比 sed 对于任何跨行更有用。在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ awk '!/\.jar/{f=0} /tomcat\.util/{f=1} !f' file
this is line 1

this is line 3


the end leave me
and me