Unix和Linux使用带SED的正则表达式详细教程

上一章Unix和Linux教程请查看:Unix和Linux的vi编辑器操作和用法
在本章中我们将详细讨论在Unix中使用SED的正则表达式。正则表达式是一个可以用来描述多个字符序列的字符串,正则表达式由几个不同的Unix命令使用,包括ed、sed、awk、grep,在一定程度上还包括vi。
这里SED代表流编辑器(stream editor),这个面向流的编辑器是专门为执行脚本而创建的。因此我们提供给它的所有输入都经过并进入STDOUT,并且它不会更改输入文件。
1、调用sed【Unix和Linux使用带SED的正则表达式详细教程】首先我们要确保有/etc/passwd文本文件的本地副本来使用sed,如前所述可以通过以下方式通过管道向sed发送数据来调用它:

$ cat /etc/passwd | sed Usage: sed [OPTION]... {script-other-script} [input-file]...-n, --quiet, --silent suppress automatic printing of pattern space -e script, --expression = script ...............................

cat命令通过管道将/etc/passwd的内容转储到sed的模式空间,模式空间是sed用于其操作的内部工作缓冲区。
2、sed通用语法以下是sed的一般语法:
/pattern/action

在这里pattern是一个正则表达式,action是下表中给出的命令之一。如果模式被省略将对上面看到的每一行执行操作,需要模式周围的斜杠字符(/),因为它们用作分隔符。
编号 访问 & 描述
1 p 打印行
2 d 删除行
3     s/pattern1/pattern2/ 用pattern2代替pattern1的第一次出现
3、使用sed删除所有行现在我们将了解如何使用sed删除所有行。再次调用sed但是sed现在应该使用编辑命令delete行,用单个字母d?表示:
$ cat /etc/passwd | sed 'd' $

与通过管道向sed发送文件不同,可以指示sed从文件中读取数据,如下面的示例所示下面的命令与前面的示例完全相同,但是没有使用cat命令:
$ sed -e 'd' /etc/passwd $

4、sed地址sed还支持地址。地址是文件中的特定位置或应用特定编辑命令的范围,当sed没有遇到地址时,它将对文件中的每一行执行操作。下面的命令将向你一直使用的sed命令添加基本地址:
$ cat /etc/passwd | sed '1d' |more user1:x:1:1:user1:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh $

注意数字1是在delete编辑命令之前添加的。这指示sed在文件的第一行执行编辑命令,在本例中sed将删除/etc/password的第一行并打印文件的其余部分。
编号 范围 & 描述
1 ‘ 4,10d’ 从第4行到第10行被删除
2 ‘ 10,4d’ 只有第10行被删除,因为sed没有反向工作
3 ‘ 4,+5d’ 它匹配文件中的第4行并删除该行,继续删除后面的5行,然后停止删除并打印其余的行
4 ‘ 2,5!d’ 这将删除除从第2行到第5行以外的所有内容
5 ‘ 1~3d’ 这将删除第一行,遍历接下来的三行然后删除第四行。Sed将继续应用此模式直到文件结束。
6 ‘ 2~2d’ 这告诉sed删除第二行,跳过下一行,删除下一行,然后重复操作,直到到达文件的末尾
7 ‘ 4,10p’ 从4号到10号的行被打印出来
8 ‘ 4,d’ 这将生成语法错误
9 ‘ ,10d’ 这也会产生语法错误
注意在使用p操作时,应该使用-n选项来避免重复行打印。查看以下两个命令之间的差异:
$ cat /etc/passwd | sed -n '1,3p'$ cat /etc/passwd | sed '1,3p'

5、替换命令用s表示的替换命令将用指定的其他字符串替换指定的任何字符串。要用一个字符串替换另一个字符串,sed需要知道第一个字符串的结束位置和替换字符串的开始位置,为此我们使用正斜杠(/)字符对两个字符串进行辅助。下面的命令用字符串user替换字符串根行的第一个匹配项。
$ cat /etc/passwd | sed 's/root/user/' user:x:0:0:root user:/root:/bin/sh user1:x:1:1:user1:/usr/sbin:/bin/sh ..........................

需要注意的是sed仅替换行上的第一个事件。如果字符串根在一行中出现多次,则只替换第一个匹配项。为了让sed执行全局替换,请在命令末尾添加字母g,如下所示:
$ cat /etc/passwd | sed 's/root/user/g' user:x:0:0:user user:/user:/bin/sh user1:x:1:1:user1:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh ...........................

6、替换标志除了g标志之外还可以传递许多其他有用的标志,你可以一次指定多个标志。
编号 标志 & 描述
1 g 替换所有匹配项,而不仅仅是第一个匹配项
2 NUMBER 只替换第NUMBER个匹配
3 p 如果进行了替换,则打印模式空间
4 w FILENAME 如果进行了替换,则将结果写入文件名
5 I or i 以大小写不敏感的方式匹配
6 M or m 除了特殊的正则表达式字符^和$的正常行为之外,这个标志还会导致^匹配换行后的空字符串,而$匹配换行前的空字符串
7、使用可选的字符串分隔符假设必须对包含正斜杠字符的字符串进行替换。在这种情况下可以通过在s后面提供指定的字符来指定不同的分隔符。
$ cat /etc/passwd | sed 's:/root:/user:g' user:x:0:0:user user:/user:/bin/sh user1:x:1:1:user1:/usr/sbin:/bin/sh

在上面的例子中,我们使用:作为分隔符而不是斜杠/,因为我们试图搜索/root而不是简单的根。
8、替换空白使用空替换字符串从/etc/passwd文件中完全删除根字符串:
$ cat /etc/passwd | sed 's/root//g' :x:0:0::/:/bin/sh user1:x:1:1:user1:/usr/sbin:/bin/sh

9、地址替换如果希望仅在第10行使用字符串quiet替换字符串sh,可以按如下方式指定它:
$ cat /etc/passwd | sed '10s/sh/quiet/g' bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh

类似地要执行地址范围替换可以执行以下操作:
$ cat /etc/passwd | sed '1,5s/sh/quiet/g' bin:x:2:2:bin:/bin:/bin/quiet sys:x:3:3:sys:/dev:/bin/quiet games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh

正如你从输出中看到的,前5行将字符串sh更改为quiet,但其余行保持不变。
10、替换命令可以使用p选项和-n选项来打印所有匹配的行,如下所示:
$ cat testing | sed -n '/root/p' root:x:0:0:root user:/root:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh

11、使用正则表达式在匹配模式时可以使用提供更多灵活性的正则表达式。检查下面的示例,它匹配所有以daemon开头的行然后删除它们:
$ cat testing | sed '/^usx/d' bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync

下表列出了在正则表达式中非常有用的四个特殊字符。
编号 字符 & 描述
1 ^ 匹配行首
2 $ 匹配行尾
3 . 匹配任何单个字符
4 * 匹配前一个字符的零次或多次出现
5 [chars] 匹配字符中的任何一个字符,其中字符是字符序列。可以使用-字符来表示字符的范围。
12、字符匹配再看几个表达来演示元字符的用法。例如下面的模式:
编号 表达式 & 描述
1 /a.c/ 匹配包含字符串(如a+c、a-c、abc、match和a3c)的行
2 /a*c/ 与ace、yacc和arctic等字符串匹配相同的字符串
3 /[tT]he/ 匹配字符串the和the
4 /^$/ 匹配空行
5 /^.*$/ 匹配一整行
6 / */ 匹配一个或多个空格
7 /^$/ 匹配空行
下表显示了一些常用的字符集:
编号 集合 & 描述
1 [a-z] 匹配单个小写字母
2 [A-Z] 匹配单个大写字母
3 [a-zA-Z] 匹配单个字母
4 [0-9] 匹配单个数字
5 [a-zA-Z0-9] 匹配单个字母或数字
13、字符类关键字一些特殊的关键字通常可用于regexp,特别是使用regexp的GNU实用程序。这些对于sed正则表达式非常有用,因为它们简化了工作并增强了可读性。
例如字符a到z和字符a到z组成了一类关键字[[:alpha:]]使用字母字符类关键字,此命令仅打印/etc/syslog.conf文件中以字母开头的行:
$ cat /etc/syslog.conf | sed -n '/^[[:alpha:]]/p' authpriv.*/var/log/secure mail.*-/var/log/maillog cron.*/var/log/cron uucp,news.crit/var/log/spooler local7.*/var/log/boot.log

下表是GNU sed中可用字符类关键字的完整列表。
编号 字符类 & 描述
1 [[:alnum:]] 字母数字[a-z A-Z 0-9]
2 [[:alpha:]] 字母 [a-z A-Z]
3 [[:blank:]] 空白字符(空格或制表符)
4 [[:cntrl:]] 控制字符
5 [[:digit:]] 数字[0-9]
6 [[:graph:]] 任何可见字符(不包括空格)
7 [[:lower:]] 小写字母[a-z]
8 [[:print:]] 可打印字符(非控制字符)
9 [[:punct:]] 标点符号
10 [[:space:]] 空格
11 [[:upper:]] 大写字母[A-Z]
12 [[:xdigit:]] 十六进制数字[0-9 a-f A-F]
14、& 引用sed元字符& 表示匹配的模式的内容。例如假设有一个名为phone.txt的文件,其中充满了电话号码,如下所示:
9999991212 9999991213

为了便于阅读需要将前三位数用圆括号括起来,为此可以使用与符号替换字符:
$ sed -e 's/^[[:digit:]][[:digit:]][[:digit:]]/(& )/g' phone.txt (999)9991212 (999)9991213

在模式部分中,首先匹配前3位数字,然后使用& 这样你就可以用括号里的3位数字代替。
15、使用多个sed命令你可以在一个sed命令中使用多个sed命令如下所示:
$ sed -e 'command1' -e 'command2' ... -e 'commandN' files

这里command1通过commandN是前面讨论的类型的sed命令。这些命令应用于文件给出的文件列表中的每一行,使用相同的机制我们可以将上面的电话号码示例写成以下形式:
$ sed -e 's/^[[:digit:]]\{3\}/(& )/g'\ -e 's/)[[:digit:]]\{3\}/& -/g' phone.txt (999)999-1212 (666)999-1213

注意在上面的例子中,我们用\{3\}替换了字符类关键字[[:digit:]]三次,这意味着前面的正则表达式匹配了三次。我们还使用\给出换行符,在运行命令之前必须将其删除。
16、反向引用与& 元字符很有用,但更有用的是在正则表达式中定义特定区域的能力。这些特殊区域可以在替换字符串中用作参考,通过定义正则表达式的特定部分,可以使用特殊的引用字符引用这些部分。
要实现泛型引用,你必须首先定义一个区域,然后再回引用该区域。要定义一个区域可以在每个感兴趣的区域周围插入反斜杠括号,使用反斜杠包围的第一个区域将由\1引用,第二个区域将由\2引用依此类推。

    推荐阅读