在本章中,我们将详细讨论在Unix中使用SED的正则表达式.
正则表达式是一个字符串,可用于描述几个字符序列.正则表达式由几个不同的Unix命令使用,包括 ed , sed , awk , grep ,以及更有限的范围, vi .
此处 SED 代表 s tream ed itor.这个面向流的编辑器专门用于执行脚本.因此,您输入的所有输入都会通过并转到STDOUT并且它不会更改输入文件.
之前我们首先,让我们确保我们有/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的模式空间.模式空间是sed用于其操作的内部工作缓冲区.
以下是sed&minus的一般语法;
/pattern/action
在这里, pattern 是正则表达式, action 是下表中给出的命令之一.如果省略 pattern ,则如上所示,对每一行执行 action .
周围的斜杠字符(/)模式是必需的,因为它们被用作分隔符.
Sr.No. | Range&描述 |
---|---|
1 | p 打印行 |
2 | d 删除行 |
3 | s/pattern1/pattern2/ 用pattern2替换第一次出现的pattern1 |
我们现在将了解如何用sed删除所有行.再次调用sed;但是sed现在应该使用编辑命令删除行,用单个字母 d :
$ cat/etc/passwd | sed'd' $
不是通过管道向文件发送文件来调用sed,而是可以指示sed读取数据来自文件,如下例所示.
以下命令与前一个示例完全相同,没有cat命令 :
$ sed -e'd'/etc/passwd $
sed还支持地址.地址是文件中的特定位置或应该应用特定编辑命令的范围.当sed遇到没有地址时,它会对文件中的每一行执行操作.
以下命令为你一直使用的sed命令添加一个基本地址 :
$ cat /etc/passwd | sed '1d' |more daemon:x:1:1:daemon:/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 命令.这指示sed在文件的第一行执行编辑命令.在此示例中,sed将删除/etc/password 的第一行并打印文件的其余部分.
我们现在将了解如何使用 sed地址范围.那么如果你想从文件中删除多行呢?您可以使用sed指定地址范围,如下所示;
$ cat /etc/passwd | sed '1, 5d' |more 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到5开始的所有行.这将删除前五行.
尝试以下地址范围 :
Sr.No. | 范围&描述 |
---|---|
1 | '4,10d' 删除从4 th 开始直到10 th 的行 |
2 | '10,4d' 只删除10个 th 行,因为sed没有反向工作 |
3 | '4,+ 5d' 这与文件中的第4行匹配,删除该行,继续删除下五行,然后停止删除并打印剩余部分 |
4 | '2,5!d' 这删除除2 nd 至5 th 行之外的所有内容 |
5 | '1~3d' 这将删除第一行,逐步执行接下来的三行,然后删除第四行. Sed继续应用此模式直到文件结束. |
6 | '2~2d' 这告诉sed删除第二行,跳过下一行,删除下一行,然后重复,直到到达文件末尾 |
7 | '4,10p' 打印从4 th 到10 th 的行 |
8 | '4,d' 这会产生语法错误 |
9 | ',10d' 这也会产生语法错误 |
注意 : 使用 p 操作时,应使用 -n 选项以避免重复行打印.检查以下两个命令之间的差异 :
$ cat /etc/passwd | sed -n '1,3p' Check the above command without -n as follows − $ cat /etc/passwd | sed '1,3p'
替换命令,用 s表示,将您指定的任何字符串替换为您指定的任何其他字符串.
要将一个字符串替换为另一个字符串,sed需要获取有关第一个字符串结束位置的信息.替换字符串开始.为此,我们继续使用正斜杠(/)字符对两个字符串进行bookending.
以下命令替换字符串行上的第一个匹配项 root ,字符串 amrood .
$ cat /etc/passwd | sed 's/root/amrood/' amrood:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh ..........................
非常重要的是要注意sed只替换一行中的第一个匹配项.如果字符串根在一行上出现多次,则只会替换第一个匹配.
对于要执行全局替换的sed,添加字母 g 到命令的结尾如下 :
$ cat /etc/passwd | sed 's/root/amrood/g' amrood:x:0:0:amrood user:/amrood:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh ...........................
除了 g 标志外,还有许多其他有用的标志可以传递,你可以一次指定多个.
Sr.No. | Flag&描述 |
---|---|
1 | g 取代所有比赛,而不仅仅是第一场比赛 |
2 | NUMBER 仅替换NUMBER th 匹配 |
3 | p 如果进行了替换,然后打印模式空间 |
4 | w FILENAME 如果进行了替换,则将结果写入FILENAME |
5 | I or i 以不区分大小写的方式匹配 |
6 | M或m 除了特殊正则表达式字符^和$的正常行为外,此标志还会导致^与empt匹配换行后的字符串和$换行符之前的空字符串 |
假设您必须对包含正斜杠字符的字符串进行替换.在这种情况下,您可以通过在 s 之后提供指定的字符来指定不同的分隔符.
$ cat /etc/passwd | sed 's:/root:/amrood:g' amrood:x:0:0:amrood user:/amrood:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh
在上面的例子中,我们使用:作为分隔符而不是斜线/因为我们试图搜索/root 而不是简单的根.
使用空替换字符串从/etc/passwd 文件中完全删除根字符串 :
$ cat /etc/passwd | sed 's/root//g' :x:0:0::/:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh
如果要用字符串<替换字符串 sh b>安静仅在第10行,你可以指定如下 :
$ cat /etc/passwd | sed '10s/sh/quiet/g' root:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/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/quiet
同样,要进行地址范围替换,您可以执行类似以下的操作;
$ cat /etc/passwd | sed '1,5s/sh/quiet/g' root:x:0:0:root user:/root:/bin/quiet daemon:x:1:1:daemon:/usr/sbin:/bin/quiet bin:x:2:2:bin:/bin:/bin/quiet sys:x:3:3:sys:/dev:/bin/quiet 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
从输出中可以看出,前五行的字符串 sh 更改为 quiet ,但其余的行保持不变.
您可以使用 p 选项以及 -n 打印所有匹配行的选项,如下 :
$ cat /etc/passwd | sed '1,5s/sh/quiet/g' root:x:0:0:root user:/root:/bin/quiet daemon:x:1:1:daemon:/usr/sbin:/bin/quiet bin:x:2:2:bin:/bin:/bin/quiet sys:x:3:3:sys:/dev:/bin/quiet 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
在匹配模式时,您可以使用提供更大灵活性的正则表达式.
检查以下示例,该示例匹配以
$ cat testing | sed -n '/root/p' root:x:0:0:root user:/root:/bin/sh [root@ip-72-167-112-17 amrood]# vi testing root:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/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
以下是删除所有以 sh &minus结尾的行的示例;
$ cat testing | sed '/sh$/d' sync:x:4:65534:sync:/bin:/bin/sync
下表列出了四个在正则表达式中非常有用的特殊字符.
Sr.No. | Character&描述 |
---|---|
1 | ^ 匹配行的开头 |
2 | $ 匹配行尾 |
3 | . 匹配任何单个字符 |
4 | * 匹配前一个字符的零次或多次出现 |
5 | [chars] 匹配chars中给出的任何一个字符,其中chars是一系列字符.您可以使用 - 字符来表示一系列字符. |
再看几个表达式来演示使用元字符.例如,以下模式 :
Sr.No. | 表达式&描述 |
---|---|
1 | /ac/ 匹配包含字符串的行,例如 a+ c , ac , abc ,匹配, a3c |
2 | /a * c/ 匹配相同的字符串以及字符串,例如 ace , yacc 和 arctic |
3 | /[tT]he/ 匹配字符串 和 |
4 | /^ $/ 匹配空行 |
5 | /^.*$/ 匹配整行不管它是什么 |
6 | /*/ 匹配一个或多个空格 |
7 | /^ $/ 匹配空白行 |
下表显示了一些经常使用的字符集 :
Sr.No. | Set&描述 |
---|---|
1 | [az] 匹配单个小写字母 |
2 | [AZ] 匹配单个大写字母 |
3 | [a-zA-Z] 匹配一个字母 |
4 | [0-9] 匹配单个数字 |
5 | [a-zA-Z0 -9] 匹配单个字母或数字 |
regexps 通常可以使用一些特殊关键字,尤其是使用 regexps的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中可用字符类关键字的完整列表.
Sr.No. | Character Class&描述 |
---|---|
1 | [[:alnum:]] 字母数字[az AZ 0-9] |
2 | [[:alpha: ]] 字母[az AZ] |
3 | [[:blank:]] 空白字符(空格或制表符) |
4 | [[:cntrl:]] 控制字符 |
5 | [[:数字:]] 数字[0-9] |
6 | [[: graph:]] 任何可见的字符(不包括空格) |
7 | [[:lower:]] 小写字母[az] |
8 | [[:print:]] 可打印字符(非控制字符) |
9 | [[:punct:]] 标点字符 |
10 | [[:space:]] 空白 |
11 | [[: upper:]] 大写字母[AZ] |
12 | [[:xdigit:]] 十六进制数字[0-9 af AF] |
sed元字符& 表示匹配的模式的内容.例如,假设您有一个名为 phone.txt 的文件,其中包含完整的电话号码,例如以下 :
5555551212 5555551213 5555551214 6665551215 6665551216 7775551217
你想做的区号(前三位数字)用括号括起,以便于阅读.为此,您可以使用&符替换字符 :
$ sed -e 's/^[[:digit:]][[:digit:]][[:digit:]]/(&)/g' phone.txt (555)5551212 (555)5551213 (555)5551214 (666)5551215 (666)5551216 (777)5551217
这里的模式部分你匹配前3个数字,然后使用& ,您将用周围的括号替换这3个数字.
您可以在单个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 (555)555-1212 (555)555-1213 (555)555-1214 (666)555-1215 (666)555-1216 (777)555-1217
注意 : 在上面的示例中,我们将其替换为 \ {3 \} ,而不是重复字符类关键字 [[:digit:]] ,这意味着前面的正则表达式匹配三次.我们还使用 \ 来提供换行符,并且必须在运行命令之前将其删除.
&符元字符很有用,但更有用的是能够在正则表达式中定义特定区域.这些特殊区域可用作替换字符串中的参考.通过定义正则表达式的特定部分,您可以引用具有特殊引用字符的那些部分.
要执行反向引用,您必须先定义一个区域,然后返回该区域.要定义区域,请在每个感兴趣的区域周围插入反斜杠括号.用反斜杠包围的第一个区域由 \1 引用,第二个区域由 \2 引用,依此类推.
假设 phone.txt 有以下文字 :
(555)555-1212 (555)555-1213 (555)555-1214 (666)555-1215 (666)555-1216 (777)555-1217
尝试以下命令 :
$ cat phone.txt | sed 's/\(.*)\)\(.*-\)\(.*$\)/Area \ code: \1 Second: \2 Third: \3/' Area code: (555) Second: 555- Third: 1212 Area code: (555) Second: 555- Third: 1213 Area code: (555) Second: 555- Third: 1214 Area code: (666) Second: 555- Third: 1215 Area code: (666) Second: 555- Third: 1216 Area code: (777) Second: 555- Third: 1217
注意 : 在上面的示例中,括号内的每个正则表达式将由 \1 , \2 反向引用,依此类推.我们在这里使用了 \ 来换行.在运行命令之前应该删除它.