📄 471.html
字号:
与行首匹配 <br>
与行末尾匹配 <br>
与任一个字符匹配 <br>
将与前一个字符的零或多个出现匹配 <br>
[ ] 与 [ ] 之内的所有字符匹配 <br>
<br>
感受规则表达式的最好方法可能是看几个示例。所有这些示例都将被 sed 作为合法地址接受,这些地址出现在命令的左边。下面是几个示例:<br>
<br>
规则<br>
表达式 描述 <br>
/./ 将与包含至少一个字符的任何行匹配 <br>
/../ 将与包含至少两个字符的任何行匹配 <br>
/^#/ 将与以 '#' 开始的任何行匹配 <br>
/^$/ 将与所有空行匹配 <br>
/}^/ 将与以 '}'(无空格)结束的任何行匹配 <br>
/} *^/ 将与以 '}' 后面跟有零或多个空格结束的任何行匹配 <br>
/[abc]/ 将与包含小写 'a'、'b' 或 'c' 的任何行匹配 <br>
/^[abc]/ 将与以 'a'、'b' 或 'c'开始的任何行匹配 <br>
<br>
在这些示例中,鼓励您尝试几个。花一些时间熟悉规则表达式,然后尝试几个自己创建的规则表达式。可以如下使用 regexp:<br>
<br>
<br>
$ sed -e '/regexp/d' /path/to/my/test/file | more<br>
<br>
<br>
<br>
<br>
<br>
这将导致 sed 删除任何匹配的行。然而,通过告诉 sed打印 regexp 匹配并删除不匹配的内容,而不是与之相反的方法,会更有利于熟悉规则表达式。可以用以下命令这样做:<br>
<br>
<br>
$ sed -n -e '/regexp/p' /path/to/my/test/file | more<br>
<br>
<br>
<br>
<br>
<br>
请注意新的 '-n' 选项,该选项告诉 sed 除非明确要求打印模式空间,否则不这样做。您还会注意到,我们用 'p' 命令替换了 'd' 命令,如您所猜想的那样,这明确要求 sed 打印模式空间。就这样,将只打印匹配部分。<br>
<br>
有关地址的更多内容<br>
目前为止,我们已经看到了行地址、行范围地址和 regexp 地址。但是,还有更多的可能。我们可以指定两个用逗号分开的规则表达式,sed 将与所有从匹配第一个规则表达式的第一行开始,到匹配第二个规则表达式的行结束(包括该行)的所有行匹配。例如,以下命令将打印从包含 "BEGIN" 的行开始,并且以包含 "END" 的行结束的文本块:<br>
<br>
<br>
$ sed -n -e '/BEGIN/,/END/p' /my/test/file | more<br>
<br>
<br>
<br>
<br>
<br>
如果没发现 "BEGIN",那么将不打印数据。如果发现了 "BEGIN",但是在这之后的所有行中都没发现 "END",那么将打印所有后续行。发生这种情况是因为 sed 面向流的特性 -- 它不知道是否会出现 "END"。<br>
<br>
C 源代码示例<br>
如果只要打印 C 源文件中的 main() 函数,可输入:<br>
<br>
$ sed -n -e '/main[[:space:]]*(/,/^}/p' sourcefile.c | more<br>
<br>
该命令有两个规则表达式 '/main[[:space:]]*(/' 和 '/^}/',以及一个命令 'p'。第一个规则表达式将与后面依次跟有任意数量的空格或制表键以及开始圆括号的字符串 "main" 匹配。这应该与一般 ANSI C main() 声明的开始匹配。<br>
<br>
在这个特别的规则表达式中,出现了 '[[:space:]]' 字符类。这只是一个特殊的关键字,它告诉 sed 与 TAB 或空格匹配。如果愿意的话,可以不输入 '[[:space:]]',而输入 '[',然后是空格字母,然后是 -V,然后再输入制表键字母和 ']' -- Control-V 告诉 bash 要插入“真正”的制表键,而不是执行命令扩展。使用 '[[:space:]]' 命令类(特别是在脚本中)会更清楚。<br>
<br>
好,现在看一下第二个 regexp。'/^}' 将与任何出现在新行行首的 '}' 字符匹配。如果代码的格式很好,那么这将与 main() 函数的结束花括号匹配。如果格式不好,则不会正确匹配 -- 这是执行模式匹配任务的一件棘手之事。<br>
<br>
因为是处于 '-n' 安静方式,所以 'p' 命令还是完成其惯有任务,即明确告诉 sed 打印该行。试着对 C 源文件运行该命令 -- 它应该输出整个 main() { } 块,包括开始的 "main()" 和结束的 '}'。<br>
<br>
下一篇<br>
既然已经触及了基本知识,我们将在后两篇文章中加快步伐。如果想看一些更丰富的 sed 资料,请耐心一些 -- 马上就有!同时,您可能想查看下列 sed 和规则表达式资源。<br>
<br>
sed 是十分强大和小巧的文本流编辑器。在本文章系列的第二篇中,Daniel Robbins 为您演示如何使用 sed 来执行字符串替换、创建更大的 sed 脚本以及如何使用 sed 的附加、插入和更改行命令。<br>
sed 是很有用(但常被遗忘)的 UNIX 流编辑器。在以批处理方式编辑文件或以有效方式创建 shell 脚本来修改现有文件方面,它是十分理想的工具。本文是前一篇介绍 sed 文章的续篇。<br>
<br>
替换!<br>
让我们看一下 sed 最有用的命令之一,替换命令。使用该命令,可以将特定字符串或匹配的规则表达式用另一个字符串替换。下面是该命令最基本用法的示例:<br>
<br>
$ sed -e 's/foo/bar/' myfile.txt <br>
上面的命令将 myfile.txt 中每行第一次出现的 'foo'(如果有的话)用字符串 'bar' 替换,然后将该文件内容输出到标准输出。请注意,我说的是每行第一次出现,尽管这通常不是您想要的。在进行字符串替换时,通常想执行全局替换。也就是说,要替换每行中的所有出现,如下所示: <br>
<br>
$ sed -e 's/foo/bar/g' myfile.txt <br>
在最后一个斜杠之后附加的 'g' 选项告诉 sed 执行全局替换。<br>
<br>
关于 's///' 替换命令,还有其它几件要了解的事。首先,它是一个命令,并且只是一个命令,在所有上例中都没有指定地址。这意味着,'s///' 还可以与地址一起使用来控制要将命令应用到哪些行,如下所示:<br>
<br>
$ sed -e '1,10s/enchantment/entrapment/g' myfile2.txt <br>
上例将导致用短语 'entrapment' 替换所有出现的短语 'enchantment',但是只在第一到第十行(包括这两行)上这样做。<br>
<br>
$ sed -e '/^$/,/^END/s/hills/mountains/g' myfile3.txt <br>
该例将用 'mountains' 替换 'hills',但是,只从空行开始,到以三个字符 'END' 开始的行结束(包括这两行)的文本块上这样做。<br>
<br>
关于 's///' 命令的另一个妙处是 '/' 分隔符有许多替换选项。如果正在执行字符串替换,并且规则表达式或替换字符串中有许多斜杠,则可以通过在 's' 之后指定一个不同的字符来更改分隔符。例如,下例将把所有出现的 /usr/local 替换成 /usr:<br>
<br>
$ sed -e 's:/usr/local:/usr:g' mylist.txt <br>
在该例中,使用冒号作为分隔符。如果需要在规则表达式中指定分隔符字符,可以在它前面加入反斜杠。<br>
<br>
规则表达式混乱<br>
目前为止,我们只执行了简单的字符串替换。虽然这很方便,但是我们还可以匹配规则表达式。例如,以下 sed 命令将匹配从 '<' 开始、到 '>' 结束、并且在其中包含任意数量字符的短语。下例将删除该短语(用空字符串替换):<br>
<br>
$ sed -e 's/<.*>//g' myfile.html <br>
这是要从文件除去 HTML 标记的第一个很好的 sed 脚本尝试,但是由于规则表达式的特有规则,它不会很好地工作。原因何在?当 sed 试图在行中匹配规则表达式时,它要在行中查找最长的匹配。在我的前一篇 sed 文章中,这不成问题,因为我们使用的是 'd' 和 'p' 命令,这些命令总要删除或打印整行。但是,在使用 's///' 命令时,确实有很大不同,因为规则表达式匹配的整个部分将被目标字符串替换,或者,在本例中,被删除。这意味着,上例将把下行:<br>
<br>
<b>This</b> is what <b>I</b> meant. <br>
变成:<br>
<br>
meant. <br>
我们要的不是这个,而是:<br>
<br>
This is what I meant. <br>
幸运的是,有一种简便方法来纠正该问题。我们不输入“'<' 字符后面跟有一些字符并以 '>' 字符结束”的规则表达式,而只需输入一个“'<' 字符后面跟有任意数量非 '>' 字符并以 '>' 字符结束”的规则表达式。这将与最短、而不是最长的可能性匹配。新命令如下:<br>
<br>
$ sed -e 's/<[^>]*>//g' myfile.html <br>
在上例中,'[^>]' 指定“非 '>'”字符,其后的 '*' 完成该表达式以表示“零或多个非 '>' 字符”。对几个 html 文件测试该命令,将它们管道输出到 "more",然后仔细查看其结果。<br>
<br>
更多字符匹配<br>
'[ ]' 规则表达式语法还有一些附加选项。要指定字符范围,只要字符不在第一个或最后一个位置,就可以使用 '-',如下所示:<br>
<br>
'[a-x]*' <br>
这将匹配零或多个全部为 'a'、'b'、'c'...'v'、'w'、'x' 的字符。另外,可以使用 '[:space:]' 字符类来匹配空格。以下是可用字符类的相当完整的列表:<br>
<br>
字符类 描述 <br>
[:alnum:] 字母数字 [a-z A-Z 0-9] <br>
[:alpha:] 字母 [a-z A-Z] <br>
[:blank:] 空格或制表键 <br>
[:cntrl:] 任何控制字符 <br>
[:digit:] 数字 [0-9] <br>
[:graph:] 任何可视字符(无空格) <br>
[:lower:] 小写 [a-z] <br>
[:print:] 非控制字符 <br>
[:punct:] 标点字符 <br>
[:space:] 空格 <br>
[:upper:] 大写 [A-Z] <br>
[:xdigit:] 十六进制数字 [0-9 a-f A-F] <br>
<br>
尽可能使用字符类是很有利的,因为它们可以更好地适应非英语 locale(包括某些必需的重音字符等等).<br>
<br>
高级替换功能<br>
我们已经看到如何执行简单甚至有些复杂的直接替换,但是 sed 还可以做更多的事。实际上可以引用匹配规则表达式的部分或全部,并使用这些部分来构造替换字符串。作为示例,假设您正在回复一条消息。下例将在每一行前面加上短语 "ralph said: ":<br>
<br>
$ sed -e 's/.*/ralph said: &/' origmsg.txt <br>
输出如下: <br>
<br>
ralph said: Hiya Jim, ralph said: ralph said: <br>
I sure like this sed stuff! ralph said: <br>
该例的替换字符串中使用了 '&' 字符,该字符告诉 sed 插入整个匹配的规则表达式。因此,可以将与 '.*' 匹配的任何内容(行中的零或多个字符的最大组或整行)插入到替换字符串中的任何位置,甚至多次插入。这非常好,但 sed 甚至更强大。<br>
<br>
那些极好的带反斜杠的圆括号<br>
's///' 命令甚至比 '&' 更好,它允许我们在规则表达式中定义区域,然后可以在替换字符串中引用这些特定区域。作为示例,假设有一个包含以下文本的文件:<br>
<br>
foo bar oni eeny meeny miny larry curly moe jimmy the weasel <br>
现在假设要编写一个 sed 脚本,该脚本将把 "eeny meeny miny" 替换成 "Victor eeny-meeny Von miny" 等等。要这样做,首先要编写一个由空格分隔并与三个字符串匹配的规则表达式。<br>
<br>
'.* .* .*' <br>
现在,将在其中每个感兴趣的区域两边插入带反斜杠的圆括号来定义区域:<br>
<br>
'(.*) (.*) (.*)' <br>
除了要定义三个可在替换字符串中引用的逻辑区域以外,该规则表达式的工作原理将与第一个规则表达式相同。下面是最终脚本:<br>
<br>
$ sed -e 's/(.*) (.*) (.*)/Victor 1-2 Von 3/' myfile.txt <br>
如您所见,通过输入 'x'(其中,x 是从 1 开始的区域号)来引用每个由圆括号定界的区域。输入如下:<br>
<br>
Victor foo-bar Von oni Victor eeny-meeny Von miny Victor larry-curly Von moe Victor jimmy-the Von weasel <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -