个性化阅读
专注于IT技术分析

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

上一章Unix和Linux教程请查看:Unix和Linux的vi编辑器操作和用法

在本章中我们将详细讨论在Unix中使用SED的正则表达式。正则表达式是一个可以用来描述多个字符序列的字符串,正则表达式由几个不同的Unix命令使用,包括ed、sed、awk、grep,在一定程度上还包括vi。

这里SED代表流编辑器(stream editor),这个面向流的编辑器是专门为执行脚本而创建的。因此我们提供给它的所有输入都经过并进入STDOUT,并且它不会更改输入文件。

1、调用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引用依此类推。

赞(0) 打赏
未经允许不得转载:srcmini » Unix和Linux使用带SED的正则表达式详细教程
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

微信扫一扫打赏