0

我有一个如下所示的 XML 文件:

<Group>
    <Name>Awesome Group</Name>
    <Notes />
    <Date>2013-04-04</Date>
    <Expires>False</Expires>
    <Icon>7</Icon>
    <Tags />
</Group>

我正在尝试使用此命令打印所有<Notes />内容</Icon>

$ sed -n '/\<Notes \/\>/ p' file.xml

请注意,我正在转义左括号和右括号以及右括号之前的正斜杠。这不会返回任何匹配项,我觉得这很奇怪。

更奇怪的是这个命令有效:

$ sed -n '/<Notes \/>/ p' file.xml

为什么这个命令有效,因为我没有转义左括号和右括号?

编辑

ruakh 很有帮助地指出 sed 有不同的实现,并且不需要转义左括号和右括号(我认为 sed 使用 Perl 语法进行正则表达式)。我发现另一个关于 Unix 和 Linux 的帖子也很有帮助:https ://unix.stackexchange.com/questions/32907/what-c​​haracters-do-i-need-to-escape-when-using-sed-in-a -sh脚本

现在我在匹配多行正则表达式时遇到问题。这怎么行不通?

$ sed -n -r '/^<Notes \/>[\S\s]*?<\/Icon>$/ p' file.xml

我尝试过使用和不使用-r(扩展模式),使用和不使用^and $,使用.*而不是[\S\s]*,所有都没有匹配

4

2 回答 2

3

在 sed 中,<>没有特殊含义,但\<有时\>会:在某些实现中,它们表示“单词开头”和“单词结尾”。例如,这个 Bash 命令:

{ echo a ; echo ba ; echo b a ; } | sed -n '/\<a/ p'

在某些系统上,将打印aand b a(在a单词的开头有一个),但不是ba(没有)。

(从你选择的标签来看,你可能已经习惯了 Perl?Perl 做了一个面向未来的保证\,当它在一个非单词字符之前时,总是会转义它。例如,<没有特殊含义,\<但是保证<无论如何都意味着。但并非所有正则表达式引擎都采用这种方法。)


编辑已编辑的问题:

Sed 一次处理一行——这是使其成为“流编辑器”的部分原因——因此多行正则表达式基本上注定要失败。但是,在您的情况下,您实际上并不需要多行正则表达式;您只想找到包含的行<Notes />和包含的(不同的)行</Icon>,并打印两者之间的所有行(包括)。为此,您可以使用地址范围,指定起始地址/<Notes \/>/和结束地址/<\/Icon>/

sed -n '/<Notes \/>/,/<\/Icon>/ p'

(参见GNU sed 用户手册中的第3.2 节“使用”选择行sed。。)

于 2013-04-04T18:01:21.033 回答
1

sed 是用于在单行上进行简单替换的出色工具,对于任何其他文本操作,您都应该使用 awk。这是一个 GNU awk 解决方案:

$ gawk -v RS='\0' '{print gensub(/.*(<Notes \/>.*<\/Icon>).*/,"\\1","")}' file
<Notes />
    <Date>2013-04-04</Date>
    <Expires>False</Expires>
    <Icon>7</Icon>

请注意,上面仅在您要求的符号之间打印,而不是符号出现的整行。

于 2013-04-04T21:14:07.847 回答