sed学习

来源:互联网 发布:java基础入门培训费用 编辑:程序博客网 时间:2024/05/22 19:26

原文来自互联网,以下仅是自己在阅读过程中,稍作整理用于自己理解。

Sed示例-----初体验

example1:

$ sed -e 'd' /etc/services

这条command做了哪几件事:  

1.  (set opinion调用sed)      用一个编辑命令 'd' 调用 sed;

2.  (基于行模式输入)             sed 打开 /etc/services文件,将一行读入其模式缓冲区;

3.  (do expected action)       执行编辑命令(“删除行”);

4.  (基于行模式输出)             然后打印模式缓冲区(缓冲区已为空)到stdout;

5.  (go to 2 in loop until end)然后,它对后面的每一行重复这些步骤。

可以看出以下点:

        1. sed对待编辑的文本是做read操作,不会modify文本;

        2. sed对文本的操作,是以批处理形式执行的;

        3. 养成使用单引号来括起 sed 命令的习惯是个好注意,这样可以禁用 shell 扩展。

example2

$ sed -e '1d' /etc/services | more

对比发现,管道符左边只比example1在编辑命令d前多了一个数字1。这个数字的逻辑量意义是行地址,用来界定后面编辑命令的有效操作范围。

example1中没有数字,编辑命令d的操作范围是全文本,example2中有数字1,编辑命令d的操作范围只针对第一行,即删除文本的第一行。进一步地,如果

$ sed -e '1,10d' /etc/services | more

表示删除从第一行到第十行的数据(包括第一行和第十行)。


带规则表达式的地址

上面的示例展示了数字地址来索引特定行,接下来展示带正则表达式匹配特定行:

sed -e '/^#/d' /etc/services | more

这条command将删除/etc/services内存副本中的所有以#开头的注释行。


规则表达式总结

使用规则表达式来表示可能会在文本中发现的模式。下面是在规则表达式中常见的特殊字符:

^        与行首匹配

$       与行尾匹配

.        与任一字符匹配

*       将与前一个字符(块)的零个或多个匹配

[]       与[ ]内的所有字符匹配


examples:

/./            将与包含至少一个字符的任何行匹配

/../           将与包含至少两个字符的任何行匹配

/^#/         将与以'#'开始的任何行匹配

/^$/         将与所有空行匹配

/}$/          将与以 '}' (无空格)结束的任何行匹配

/} *$/        将与以 '}' 后面跟有零或多个空格结束的任何行匹配

/[abc]/     将与包含小写字符'a'、'b'或'c'的任何行匹配

/^[abc]/   将与以'a'、'b'或'c'开始的任何行匹配


sed使用regexp的通用模板:

$ sed -e -n '/regexp/p' /path/to/my/test/file | less

'-n' 选项,该选项告诉 sed 除非明确要求打印模式空间,否则不这样做,而p命令正是用来显式地要求sed开启打印模式。


有关地址的更多内容

和行索引地址区间类似,规则表达式也存在索引地址区间,如下:

$ sed -n -e '/BEGIN/,/END/p' /my/test/file | more

/BEGIN/     是索引地址区间左端点,它指明了从匹配到的第一个行开始

/END/         是索引地址区间右端点,它指明了从匹配到的第一个行结束

所有中间行作为操作域。例如:

匹配文件data.txt的内容是:

p1

p1

p2

p2

那么,

$ sed -n -e '/p1/, /p2/p' data.txt

p1             <-----------------------  这是/p1/模式匹配到的第一个匹配行

p1

p2             <----------------------- 这是/p2/模式匹配到的第一个匹配行


代码格式良好时,利用下面的command可以输出source.c中的main函数:

$ sed -n -e '/main[[:space:]]*(/,/^}/p' source.c | more

[[:space:]]    是一个特殊的关键字,它告诉 sed 与 TAB 或空格匹配。或者[ -V]替换之。

上面的命令意思就是:

打印

...main    (...           <-------开始行

}                              <-------结束行


替换!

sed 最有用的命令之一,替换命令,可以将特定字符串或匹配的规则表达式用另一个字符串替换。

$ sed -e 's/foo/bar/' myfile.txt                <---------- 将 myfile.txt 中每行第一次出现的 'foo'(如果有的话)用字符串 'bar' 替换,然后将该文件内容输出到标准输出。

$ sed -e 's/foo/bar/g' myfile.txt              <---------- 将myfile.txt 中每行出现的 所有'foo'(如果有的话)用字符串 'bar' 替换,然后将该文件内容输出到标准输出。

在最后一个斜杠之后附加的 'g' 选项告诉 sed 执行全局替换。


s/// 替换命令说明:

它是一条命令,g是它的一个选项。

可以使用行索引地址区间,来约束操作域。如: $ sed -e '1,10s/foo/bar/g' myfile.txt          表示对1到10行执行替换命令

's///' 命令的另一个妙处是 '/' 分隔符有许多替换选项。如果正在执行字符串替换,并且规则表达式或替换字符串中有许多斜杠,则可以通过在 's' 之后指定一个不同的字符来更改分隔符。在Perl的正则表达式中,有着类似的语法规则。Unix味儿十足。


规则表达式混乱  -----------  既是文本处理的法宝,也是一层层一眼望不穿的迷雾

解析原则:

1. 从左向右,按照语法规则划分出意群,对每个意群做代换;

2. 对每一个意群做语义分析;

2. 对意群的划分,按照最小意群规则,依次往外拓展。外层的元操作是对内层的意群的叠加描述。

example:

myfile.html的内容如下

<b>This</b> is what <b>I</b> meant.

我想把所有的tag删掉,即把所有的<...>模式匹配出来的字符串从中删去。首先尝试下面的命令和对应的结果:

$ sed -e 's/<.*>//g' myfile.html
 meant.

没有达到预期的编辑效果,why?

原因就在于s/// 命令做最长匹配,那 <.*>在myfile.html中的最长匹配就是<b>This</b> is what <b>I</b>

由此可知,使用s///失败的根本原因在于没有正确地分析、设计出对应的匹配模式。

接下来我们来尝试设计出可用的匹配模式,第一次可能觉得有点难以理解,但多尝试就会发现这是一个很自然的过程:

解析正则表达式的思维方式正好相反,设计正则表达式按照由外到内

首先我们用自然语言来清晰地做一次描述:

匹配出文本中所有的<...>标签,...内容可以是任意不包含>的字符串。

==> /<P1>/g,P1不包含>的任意字符串         就是我们要找的匹配模式

==> 接下来实现P1,根据P1的描述,P1=P2*,P2是除>以外的任意字符

==> 接下来实现P2,根据P2的描述,P2=[^>]

==>至此分解求值结束,逆向回代可得原来的匹配模式是/<[^>]*>/g


原创粉丝点击