sed的正则匹配如何实现非贪婪?

sed的正则用的是BREs/EREs,不支持非贪婪模式。当然有一些方法可以实现非贪婪,比如:

$ echo abcOabcdOabc | sed 's/.*O//'


结果是​​abc​​;

$ echo abcOabcdOabc | sed 's/[^O]*O//'


结果是​​abcdOacb​​,变相实现了非贪婪的匹配。

但如果是这种情况:

<div>...</div>blabla<div>...</div>


如果想用sed去除前后的​​<div>...</div>​​只留下​​blabla​​,用​​s/<div>.*<\/div>//​​会把blabla也吃掉,又没法用​​[^div]​​来实现对​​div​​整串的不匹配,那么要怎样实现非贪婪的匹配呢?



我试了下这样可以, ​​echo '<div>...</div>blabla<div>...</div>' | sed 's/<div>[^<]\+<\/div>//g'​​;

如果你是要从html/xml中提取信息的话, 还是用支持DOM操作的​​东西​​作处理吧;

正则太费时间, 正确性也不好把握

 



sed 系列: 用正则表达式查找和替换

博客分类:


 


The `s’ command is probably the most important in `sed’ and has a lot of different options.


The `s’ command attempts to match the pattern space against the supplied REGEXP; if the match is successful, then that portion of the pattern space which was matched is replaced with REPLACEMENT.


Syntax:

#sed 'ADDRESSs/REGEXP/REPLACEMENT/FLAGS' filename

#sed 'PATTERNs/REGEXP/REPLACEMENT/FLAGS' filename


s is substitute command

/ is a delimiter

REGEXP is regular expression to match

REPLACEMENT is a value to replace


LAGS can be any of the following


g Replace all the instance of REGEXP with REPLACEMENT

n Could be any number,replace nth instance of the REGEXP with REPLACEMENT.

p If substitution was made, then prints the new pattern space.

i match REGEXP in a case-insensitive manner.

w file If substitution was made, write out the result to the given file.

We can use different delimiters ( one of @ % ; : ) instead of /

建立测试文件

$ cat thegeekstuff.txt

# Instruction Guides

1. Linux Sysadmin, Linux Scripting etc.

2. Databases - Oracle, mySQL etc.

3. Security (Firewall, Network, Online Security etc)

4. Storage in Linux

5. Productivity (Too many technologies to explore, not much time available)

#  Additional FAQS

6. Windows- Sysadmin, reboot etc.


例子1:用Linux-Unix替换Linux

$ sed 's/Linux/Linux-Unix/' thegeekstuff.txt

# Instruction Guides

1. Linux-Unix Sysadmin, Linux Scripting etc.

2. Databases - Oracle, mySQL etc.

3. Security (Firewall, Network, Online Security etc)

4. Storage in Linux-Unix

5. Productivity (Too many technologies to explore, not much time available)

#  Additional FAQS

6. Windows- Sysadmin, reboot etc.


例子2:用s//g替换所有

$ sed 's/Linux/Linux-Unix/g' thegeekstuff.txt

# Instruction Guides

1. Linux-Unix Sysadmin, Linux-Unix Scripting etc.

2. Databases - Oracle, mySQL etc.

3. Security (Firewall, Network, Online Security etc)

4. Storage in Linux-Unix

5. Productivity (Too many technologies to explore, not much time available)

#  Additional FAQS

6. Windows- Sysadmin, reboot etc.


例子3:用s//2只替换第二个单词

$ sed 's/Linux/Linux-Unix/2' thegeekstuff.txt

# Instruction Guides

1. Linux Sysadmin, Linux-Unix Scripting etc.

2. Databases - Oracle, mySQL etc.

3. Security (Firewall, Network, Online Security etc)

4. Storage in Linux

5. Productivity (Too many technologies to explore, not much time available)

#  Additional FAQS

6. Windows- Sysadmin, reboot etc.


例子4:用s//gpw替换所有单词并打印和写入文件

$ sed -n 's/Linux/Linux-Unix/gpw output' thegeekstuff.txt

1. Linux-Unix Sysadmin, Linux-Unix Scripting etc.

4. Storage in Linux-Unix

$ cat output

1. Linux-Unix Sysadmin, Linux-Unix Scripting etc.

4. Storage in Linux-Unix


例子5:模式匹配替换

$ sed '/\-/s/\-.*//g' thegeekstuff.txt

# Instruction Guides

1. Linux Sysadmin, Linux Scripting etc.

2. Databases

3. Security (Firewall, Network, Online Security etc)

4. Storage in Linux

5. Productivity (Too many technologies to explore, not much time available)

#  Additional FAQS

6. Windows


例子6:删除每行的最后几个字母

$ sed 's/...$//' thegeekstuff.txt

# Instruction Gui

1. Linux Sysadmin, Linux Scripting e

2. Databases - Oracle, mySQL e

3. Security (Firewall, Network, Online Security e

4. Storage in Li

5. Productivity (Too many technologies to explore, not much time availab

#  Additional F

6. Windows- Sysadmin, reboot e


例子7:删除所有注释行

$  sed -e 's/#.*//' thegeekstuff.txt


1. Linux Sysadmin, Linux Scripting etc.

2. Databases - Oracle, mySQL etc.

3. Security (Firewall, Network, Online Security etc)

4. Storage in Linux

5. Productivity (Too many technologies to explore, not much time available)


6. Windows- Sysadmin, reboot etc.


例子8:删除所有注释行和空行

$ sed -e 's/#.*//;/^$/d'  thegeekstuff.txt

1. Linux Sysadmin, Linux Scripting etc.

2. Databases - Oracle, mySQL etc.

3. Security (Firewall, Network, Online Security etc)

4. Storage in Linux

5. Productivity (Too many technologies to explore, not much time available)

6. Windows- Sysadmin, reboot etc.


例子9:Dos到unix格式转换

Copy the DOS file to Unix, you could find \r\n in the end of each line.


This example converts the DOS file format to Unix file format using sed command.


$sed 's/.$//' filename


例子10:移除html标签(有待商榷)

In this example, the regular expression given in the sed command matches the html tags and replaces with the empty.


$ sed -e 's/<[^>]*>//g'

This <b> is </b> an <i>example</i>.

This  is  an example.

 

 

sed、awk工具可以实现文本替换并且把替换的文本输出到屏幕上

sed和awk都是流式编辑器,是针对文档的行来操作的。sed通常用来替换操作。

示例的文本内容,以下操作根据此文本。

[root@linuxidc ~]# cat test.txt 

rot:x:0:0:rot:/rot:/bin/bash

root:x:0:0:root:/root:/bin/bash

daemon:x:2:2:daemon:/sbin:/sbin/nologin

rooooot:x:0:0/roooooot:/bin/bash

11111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

1、打印某一行

sed -n 'n'p filename 单引号内的n是一个数字,表示第几行;p也可以写到引号内;

示例,打印passwd第3-5行;

[root@linuxidc ~]# sed -n '3,5'p /etc/passwd

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

打印所有行

[root@linuxidc ~]# sed -n '1,$'p /etc/passwd

打印某一行,并且要显示行号,需要和grep一起使用;

[root@localhost ~]# grep -n '.*' test.txt | sed -n '1'p

1:rrt

2、打印包含某个字符串的行

字符串需要用/ /括起来;grep中的特殊符号^ $ . * 同样适用于sed中。

[root@linuxidc ~]# sed -n '/root/'p /etc/passwd

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

打印包含/sbin/nologin的行,/需要进行脱意;

[root@linuxidc ~]# sed -n '/\/sbin\/nologin/'p passwd 

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

打印以d开头的行;打印以in结尾的;打印r与o字母中间有2个任意字符的;打印包含2个o及多个o的行;

[root@linuxidc ~]# sed -n '/^d/'p test.txt 

daemon:x:2:2:daemon:/sbin:/sbin/nologin

[root@linuxidc ~]# sed -n '/in$/'p test.txt 

daemon:x:2:2:daemon:/sbin:/sbin/nologin

[root@linuxidc ~]# sed -n '/r..o/'p test.txt

rooooot:x:0:0/roooooot:/bin/bash

[root@linuxidc ~]# sed -n '/ooo*/'p test.txt

root:x:0:0:root:/root:/bin/bash

rooooot:x:0:0/roooooot:/bin/bash

3、-e可以实现多个行为

[root@linuxidc ~]# sed -e '1'p -e '/111/'p -n test.txt 

rot:x:0:0:rot:/rot:/bin/bash

11111111111111111111111111111111

可以用-e写多个;-e相当于传送带,先匹配最前面的打印,再匹配后面的打印,所以第一行会打印2次;

[root@localhost ~]# sed -e '/root/p' -e '/bash/p' -n 1.txt

root:x:0:0:root:/root:/bin/bash

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

user1:x:500:500::/home/user1:/bin/bash

user2:x:501:501::/home/user2:/bin/bash

-e后面也可以用;分号;-n不能写到-e的后面,可以写在-e的前面或最后面;

[root@localhost ~]# sed -e '/root/p;/bash/p' -n 1.txt

root:x:0:0:root:/root:/bin/bash

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

user1:x:500:500::/home/user1:/bin/bash

user2:x:501:501::/home/user2:/bin/bash

4、删除某行或者多行

‘d’ 这个字符就是删除的动作了,不仅可以删除指定的单行以及多行,而且还可以删除匹配某个字符的行,另外还可以删除从某一行一直到文档末行。

示例,删除第一行;删除1-3行;删除包含root关键词的行;删除第3行到最后一行所有行;

[root@linuxidc ~]# sed '1'd test.txt 

root:x:0:0:root:/root:/bin/bash

daemon:x:2:2:daemon:/sbin:/sbin/nologin

rooooot:x:0:0/roooooot:/bin/bash

11111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

[root@linuxidc ~]# sed '1,3'd test.txt 

rooooot:x:0:0/roooooot:/bin/bash

11111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

[root@linuxidc ~]# sed '/root/'d test.txt

rot:x:0:0:rot:/rot:/bin/bash

daemon:x:2:2:daemon:/sbin:/sbin/nologin

rooooot:x:0:0/roooooot:/bin/bash

11111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

[root@linuxidc ~]# sed '3,$'d test.txt 

rot:x:0:0:rot:/rot:/bin/bash

root:x:0:0:root:/root:/bin/bash

5、替换字符或替换字符串

示例,替换第一行字母r为R;替换1-2行中ot为to;替换所有行中ot为to;

[root@localhost ~]# sed '1s/r/R/g' test.txt 

RRt

[root@linuxidc ~]# sed '1,2s/ot/to/g' test.txt 

rto:x:0:0:rto:/rto:/bin/bash

roto:x:0:0:roto:/roto:/bin/bash

daemon:x:2:2:daemon:/sbin:/sbin/nologin

rooooot:x:0:0/roooooot:/bin/bash

11111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

[root@linuxidc ~]# sed 's#ot#to#g' test.txt 

rto:x:0:0:rto:/rto:/bin/bash

roto:x:0:0:roto:/roto:/bin/bash

daemon:x:2:2:daemon:/sbin:/sbin/nologin

rooooto:x:0:0/roooooto:/bin/bash

11111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

与vim编辑器里面替换一样的命令格式,s代表替换,g代表全局,不加g的话只替换行的第一个;可以使用# @作为分隔符。

1s代表只替换第一行;1,3s代表第一行到第三行;不加行数的话默认为全部行。

示例,删除文档中所有的数字's/[0-9]//g'  如删除文档中所有的字母's/[a-zA-Z]//g'删除所有的数字和字母's/[0-9a-zA-Z]//g'

[root@linuxidc ~]# sed 's/[0-9]//g' test.txt 

rot:x:::rot:/rot:/bin/bash

root:x:::root:/root:/bin/bash

daemon:x:::daemon:/sbin:/sbin/nologin

rooooot:x::/roooooot:/bin/bash

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

示例,删除文档中所有的字母

[root@linuxidc ~]# sed 's/[a-z]//g' 1.txt 

::0:0:/://

::11:0::/://

::11:0::/://

::0:0:/://

1111111111111111111111111111111

示例,删除文档中不是英文字母的(数字和特殊符号)

[root@linuxidc ~]# sed 's/[^a-z]//g' 1.txt 

rotxrotbinbash

operatorxoperatorrootsbinnologin

operatorxoperatorroootsbinnologin

rooootxroooootbinbash

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

示例,删除文档中不是数字的(英文字母和特殊符号)

[root@linuxidc ~]# sed 's/[^0-9]//g' 1.txt 

00

110

110

00

1111111111111111111111111111111

示例,把文档中的小写字母全部替换为大写字母 's/[a-z]/\u&/g'

[root@linuxidc ~]# sed 's/[a-z]/\u&/g' 1.txt 

ROT:X:0:0:/ROT:/BIN/BASH

OPERATOR:X:11:0:OPERATOR:/ROOT:/SBIN/NOLOGIN

OPERATOR:X:11:0:OPERATOR:/ROOOT:/SBIN/NOLOGIN

ROOOOT:X:0:0:/ROOOOOT:/BIN/BASH

1111111111111111111111111111111

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

示例,把文档中的大写字母全部替换为小写字母 's/[A-Z]/\l&/g'

[root@linuxidc ~]# sed 's/[A-Z]/\l&/g' 1.txt 

rot:x:0:0:/rot:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rooot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

替换的同时加-n p 打印特定的行;

[root@linuxidc ~]# sed -n '1s/[a-z]/\u&/g'p 1.txt 

ROT:X:0:0:/ROT:/BIN/BASH

6、调换二个字符串的位置

sed -r 's/([^:]+)(:.*:)([^:]+$)/\3\2\1/'

[^:]非冒号,不是冒号的所有字符

-r, --regexp-extended  在脚本中使用扩展正则表达式; 加r选项的意思为后面不用再加脱意\ 

( )括号括起来是分段的意思,

\3\2\1    是代表3调换1,后面的内容调换到前面

示例,aa与ff调换;加-r选项不用加脱意符号\;不加-r ( )括号左右都需要加\脱意;调换多行用最后一个;

[root@localhost ~]# cat 1.txt 

aa:bb:cc:dd:ee:ff

[root@localhost ~]# sed -r 's/(aa)(.*)(ff)/\3\2\1/' 1.txt

ff:bb:cc:dd:ee:aa

[root@localhost ~]# sed 's/\(aa\)\(.*\)\(ff\)/\3\2\1/' 1.txt 

ff:bb:cc:dd:ee:aa

[root@localhost ~]# sed -r 's/([^:]+)(:.*:)([^:]+$)/\3\2\1/' 1.txt 

ff:bb:cc:dd:ee:aa

示例,rot与/bin/bash进行调换

[root@localhost ~]# grep 'rot' test.txt

rot:x:0:0:rot:/rot:/bin/bash

[root@localhost ~]# grep 'rot' test.txt |sed 's/\(rot\)\(.*\)\(\/bin\/bash\)/\3\2\1/'

/bin/bash:x:0:0:rot:/rot:rot

[root@localhost ~]# grep 'rot' test.txt |sed -r 's/(rot)(.*)(/bin/bash)/\3\2\1/'

sed:-e 表达式 #1,字符 18:“s”的未知选项

[root@localhost ~]# grep 'rot' test.txt |sed -r 's/(rot)(.*)(\/bin\/bash)/\3\2\1/'

/bin/bash:x:0:0:rot:/rot:rot

加-r  后()内的/bin/bash 也还需要脱意才可以;

-i 选项    直接替换字符,并且保存原文件里面。使用i选项前,记得备份原文件。

[root@localhost ~]# sed -r -i 's/([^:]+)(:.*:)([^:]+$)/\3\2\1/' 1.txt 

[root@localhost ~]# cat 1.txt 

ff:bb:cc:dd:ee:aa

在sed命令中引入shell变量 ​​http://www.linuxidc.com/Linux/2014-03/97896.htm​

Linux下Shell编程——sed命令基本用法 ​​http://www.linuxidc.com/Linux/2013-06/85526.htm​

Unix文本处理工具之sed  ​​http://www.linuxidc.com/Linux/2013-08/89315.htm​

sed 高级用法 ​​http://www.linuxidc.com/Linux/2014-09/106961.htm​

sed命令详解与示例 ​​http://www.linuxidc.com/Linux/2014-11/109325.htm​

本文永久更新链接地址:​​http://www.linuxidc.com/Linux/2015-04/116309.htm​

 

 

 



正则表达式(grep)元字符及模式匹配的介绍及sed高级应用选项

当要查看文本中特定字符的时候,我们会经常用到GREP、SED、AWK,今天我们一起来学习下Linux中的文本过滤工具GREP和SED的基本使用:

正则表达式: 

定义: 

是一些字符或是特殊字符串模式的集合。 

功能:根据模式搜索文本,并将符合模式的文本行显示出来。 

Pattern(模式): 

文本字符和正则表达式的元字符组合而成匹配条件 

grep:

grep简介 

grep(global search regular RE) < /span>and print out the line,全面搜索正则表达式并把行打印出来 

是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。 

Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。 

egrep是grep的扩展,支持更多的RE元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符 

表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

grep是很常见也很常用的命令,它最重要的功能就是进行字符串数据的比较,然后将符合用户要求的字符串显示出来。 

在这里需要说明的是,grep在数据中查找一个字符串时,是以”整行“为单位来进行数据选取的。也就是说,假如一个文件内有10行,其中有两行具有 

所搜索的字符串,则将那两行显示在屏幕上,其它则丢去。 

注:默认情况下正则表达式工作在贪婪模式下 

grep [options] PATTERN [FILE...] 

-a:在二进制文件夹中,以文本文件的方式搜索数据。 

-i:忽略大小写 

--color:将匹配的字符串以颜色基于现实 

-v:反向查询,即显示出没有被‘搜索字符串’内容的哪一行 

-o:只显示被模式匹配的字符串 

grep -o 'root' /etc/passwd 

root 

.... 

-n:输出行号 

-c:计算找到‘搜索字符串’的次数 

-A:# 匹配结果并将匹配结果的后#行一并显示 

-B: # 匹配结果并将匹配结果的前#行一并显示 

-C:A and b 显示匹配结果前和后各几行。 

正则表达式就是里面有一些元字符,这些字符不表示它本身的意思,而表示通配的意义。

介绍grep进行文件搜索时所用到的元字符并加以介绍

搜索特定字符串、利用[]来搜索集合字符、任意一个字符(.)与重复字符(*)、 

行首与行尾字符^$、限定连接重复字符范围{}、位置锚定、组

下面我们就来一起学习元字符的含义: 

^ : 锚定行首 

例如: 

'^root':表示以root作为行首进行查找 

$ : 锚定行尾 

例如: 

'nologin$':表示查找以nologin结尾所匹配的行 

. : 匹配任意单个字符 

例如: 

'r..t':表示查找以r开头,t结尾并且中间存在两个字符匹配的行 

* : 一个单字符后紧跟*,匹配0个或多个此单字符 

例如: 

'ok*':表示以o为开头后面可以没有k个字符,也可以出现多次 

.*: 任意字符 

例如: 

'root.*':表示查找以root开头后面跟任意字符所匹配的行 

[]:匹配[]内字符序列范围 

例如: 

'[a-z]'表示匹配[]任意一个小写字母 

[^]:匹配[]内以外的字符串 

例如: 

'[^root]':表示除root以外的行 

^$:显示空白行 

例如: 

'^$':表示以空白行作为模式并显示匹配的行 

\<: 其后面的任意string必须作为单词首部出现 

例如: 

'\ 

\>: 其前面的任意string必须作为一个单词尾部出现 

例如: 

'root\>':表示查找以root作为模式而且必须出现在行尾 

\: 以string为整体并进行对文本文件进行查找 

例如: 

'\':表示以root为单词并进行搜索 

\(\):分组 

例如: 

\(ab\)*:把ab当作整体,ab可以出现0次,1次,或多次 

\(\)\1:引用第一个左括号以及与之对应的右括号所包括的所有内容 

\2: 引用第二个左括号以及与之对应的右括号所包括的所有内容 

\3: 引用第三个左括号以及与之对应的右括号所包括的所有内容 

例如: 

\(ab\)\1:表示以ab为以个整体显示,并引用前面ab字符串显示出来

\ :用来注释一个元字符的特殊含义。因为有在shell中一些元字符有特殊含义。 

例如: 

'\/'表示查找以'/'作为模式进行查找 

pattern\{m\}:用来匹配前面pattern出现n次 

例如: 

'root\{2\}:表示匹配root字符串而且必须出现2次 

pattern\{m, \}:用来匹配前面pattern至少m次,多则不限 

例如:'root\{1, \}:表示至少出现1次root,多则不限 

pattern\{m,n\}:用来匹配前面pattern至少m次,至多n次 

例如: 

'root\{1,2\}:表示至少出现1次root,至多2次

EGREP: 

egrep和grep -E的元字符扩展集 

+:匹配一个或多个先前的字符。如:'[a-z]+able',匹配一个或多个小写字母后跟able的串,如loveable,enable,disable等。 

?:匹配零个或多个先前的字符。如:'gr?p'匹配gr后跟一个或没有字符,然后是p的行。 

a|b|c:匹配a或b或c。如:grep|sed匹配grep或sed 

():分组符号,如:love(able|rs)ov+匹配loveable或lovers,匹配一个或多个ov。 

x{m},x{m,},x{m,n}:作用同x\{m\},x\{m,\},x\{m,n\}

POSIX字符类:

[[:space:]]:所有空格字符 

[[:punct:]]:标点符号 

[[:lower:]]:小写字母 

[[:upper:]]:大写字母 

[[:digit:]]:数字 

[[:alnum:]]:数字和大小写字母

sed基本用法:

sed(Stream EDitor):它是一种流编辑器 

sed:文本编辑器,而不是字处理器,只是操作纯ASCII码文本的,其次它在操作文本的时候,是按行进行的,逐行进行。 

sed的主要功能是实现逐行处理文本的,所以我们称它为行编辑器。

sed的处理机制: 

每当处理一个文本文件时,它不会直接编辑文本文件的本身,而是将文本文件的内容逐行读取到内存空间里,而后在内存空间里完成编辑工作,随后将编辑出的结 

果以标准输出显示到屏幕上。 

我们称这个内存空间成为模式空间。

sed: 模式空间 

默认不编辑原文本文件本身,仅对模式空间中的数据做处理;而后将处理结束后,将模式空间打印至屏幕。

sed [options] 'AddressCommand' file ... 

-n: 静默模式,不再默认显示模式空间中的内容,只显示符合条件的行。 

-i: 直接修改原文件 

-e SCRIPT -e SCRIPT:可以同时执行多个脚本 

-f /PATH/TO/SED_SCRIPT 

sed -f /path/to/scripts file 

-r: 表示使用扩展正则表达式

Address: 

1、StartLine,EndLine 

比如1,10,表示第一行到第10行 

$:表示最后一行 

$-1:表示倒数第二行 

2、/RegExp/:支持正则表达式 

/^root/ 

3、/pattern1/,/pattern2/ 

第一次被pattern1匹配到的行开始,至第一次被pattern2匹配到的行结束,这中间的所有行 

4、LineNumber 

指定的行 

5、StartLine, +N 

从startLine开始,向后的N行; 

'1.+2': 

Command: 

d: 删除符合条件的行; 

For example:删除/etc/inittab文件中1到10行的内容 

# sed '1,10d' /etc/inittab 

For example:删除/etc/passwd文件中包括hdoop的行 

# sed '/hdoop/d'/etc/passwd 

p: 显示符合条件的行; 

For example:显示/etc/passwd文件中以hdoop开头的行 

# sed '/^hdoop/p' /etc/passwd 

a \string: 在指定的行后面追加新行,内容为string 

For example:显示/etc/passwd文件中以hdoop开头的行后面追加“I am hdoop” 

# sed '/^hdoop/a \I am hdoop /etc/passwd 

如果想加两行的话,我可以使用换行符 \n:可以用于换行 

i \string: 在指定的行前面添加新行,内容为string 

For example:显示/etc/passwd文件中以hdoop开头的行前面追加“I am hdoop” 

# sed '/^hdoop/i \I am hdoop' /etc/passwd 

r FILE: 将指定的文件的内容添加至符合条件的行处 

For example:在/etc/passwd文件中第二行后面追加/etc/inittab文件中的内容 

# sed '2r /etc/inittab /etc/passwd 即可: 

如果是在指定第一行和第二行后面添加指定文件内容的行 

# sed '1,2r /etc/inittab /etc/passwd 

w FILE: 将地址指定的范围内的行另存至指定的文件中; 

For example:在/etc/passwd文件中以hdoop开头的行保存至/tmp/hdoop.bak 

# sed '/^hdoop/w /tmp/hdoop.bak' /etc/passwd 

s/pattern/string/修饰符: 查找并替换,默认只替换每行中第一次被模式匹配到的字符串 

For example:查找/etc/passwd文件中hdoop字符换成大写的hoop 

# sed 's/hdoop/HDOOP/' /etc/passwd 

修饰符 

g: 全局替换 

i: 查找时忽略字符大小写

\(\), \1, \2 

For example:将下面的like修改为liker,love修改为lover 

l..e: like-->liker 

love-->lover

# sed 's#\(l..k\)#\1r#g' /tmp/text 

# sed 's#l..k#&r#g' /tmp/text 

&: 引用模式匹配整个串

For example:将下面的小写l换成大小l 

like-->Like 

love-->Love 

# sed 's#l\(..e\)#L\1#g' sed.text 

grep和sed命令的使用,就先告一段落。

 

 

Shell正则表达式之grep、sed、awk实操笔记


这篇文章主要介绍了Shell正则表达式之grep、sed、awk实操笔记,本文使用grep、sed、awk配合正则达到了一些需求和目的,需要的朋友可以参考下


 


最近一直在研究shell脚本这块,刚好闲下来整了下自己手头上比较好的资料中的一些范例,以下是我整理的鸟哥私房菜里面正则表达式里面比较基础的一些语法详解,适合新手查阅。

首先先复制一段范例:


复制代码 代码如下:


# vi regular_express.txt

-------------------------------

"Open Source" is a good mechanism to develop programs.

apple is my favorite food.

Football game is not use feet only.

this dress doesn't fit me.

However, this dress is about $ 3183 dollars.

GNU is free air not free beer.

Her hair is very beauty.

I can't finish the test.

Oh! The soup taste good.

motorcycle is cheap than car.

This window is clear.

the symbol '*' is represented as start.

Oh!My god!

The gd software is a library for drafting programs.

You are the best is mean you are the no. 1.

The world <Happy> is the same with "glad".

I like dog.

google is the best tools for search keyword.

goooooogle yes!

go! go! Let's go.

# I am VBird

--------------------------------


设置语系为C


复制代码 代码如下:


#export LANG=C


grep

1.搜寻特定字符串"the"

注: n为显示行号


复制代码 代码如下:


# grep -n 'the' regular_express.txt


2.反向搜寻特定字符串"the"


复制代码 代码如下:


# grep -vn 'the' regular_express.txt


3.取得任意大小写"the"的这个字符串


复制代码 代码如下:


# grep -in 'the' regular_express.txt


4.利用括号 [] 来搜寻集合字符

搜索test或taste这两个单词时,发现他们有共同的't?st',所以可以这么搜寻


复制代码 代码如下:


# grep -n 't[ae]st' regular_express.txt


这样其实就是在找t[a]st和t[e]st这两个分开的字符

如果搜索有 oo 的字符时,则可以使用:


复制代码 代码如下:


# grep -n 'oo' regular_express.txt


如果搜索oo时不想搜到 oo 前面有 g 的话,我们可以利用反向选择[^]来达成:


复制代码 代码如下:


# grep -n '[^g]oo'  regular_express.txt


如果搜索oo前面不想有小写字符,则:


复制代码 代码如下:


# grep -n '[^a-z]oo' regular_express.txt


注: 大写英文/小写英文/数字 可以使用 [a-z]/[A-Z]/[0-9]等方式来书写,也可以写在一起

[a-zA-Z0-9]表示要求字符串是数字以及英文

如果我们要取得有数字的那行,则:


复制代码 代码如下:


# grep -n '[0-9]' regular_express.txt


注:但考虑到语系对编码顺序的影响,因此除了连续编码使用减号[-]外,也可以用[:lower:]代替a-z 以及 [:digit:] 代替0-9 使用


复制代码 代码如下:


# grep -n '[^[:lower:]]oo' regular_express.txt

# grep -n '[[:digit:]]' regular_express.txt


5.显示行首为'the'的字符串


复制代码 代码如下:


# grep -n '^the' regular_express.txt


显示行首是小写字符


复制代码 代码如下:


# grep -n '^[a-z]' regular_express.txt


6.显示行尾为点 . 的那一行


复制代码 代码如下:


# grep -n '\.$' regular_express.txt


7.显示5-9行数据


复制代码 代码如下:


# cat -An regular_express.txt |head -n 10 |tail -n 6


8.显示空白行


复制代码 代码如下:


# grep -n '^$' regular_express.txt


9.找出g??d字符串,起头g结束d的四个字符串


复制代码 代码如下:


# grep -n 'g..d' regular_express.txt


10. o*代表空字符(就是有没有字符都可以)或者一个到N个o字符,所以grep -n 'o*' regular_express.txt就会把所有行全部打印出来,

11.oo*代表o+空字符或者一个到N个o字符,所以grep -n 'oo*' regular_express.txt就会把o,oo,ooo等的行全部打印出来

12."goo*g"代表gog,goog,gooog...等


复制代码 代码如下:


# grep -n 'goo*g' regular_express.txt


13.找出含g...g字符串的行

注: .代表任意字符, .*则就代表空字符或者一个到N个任意字符


复制代码 代码如下:


# grep -n 'g.*g' regular_express.txt


14.找出含有数字的行


复制代码 代码如下:


# grep -n '[0-9][0-9]*' regular_express.txt


或# grep -n '[0-9]' regular_express.txt

15.找出含两个o的字符串

注:{}因为在shell里有特殊意义,所以需要加跳脱符\来让其失去意义


复制代码 代码如下:


# grep -n 'o\{2\}'  regular_express.txt


找出g后含2到5个o然后以g结尾的字符串


复制代码 代码如下:


# grep -n 'go\{2,5\}g'  regular_express.txt


找出g后含2以上的o然后以g结尾的字符串


复制代码 代码如下:


# grep -n 'go\{2,\}g'  regular_express.txt


总结:

^word     表示带搜寻的字符串(word)在行首

word$     表示带搜寻的字符串(word)在行尾

.         表示1个任意字符

\         表示转义字符,在特殊字符前加\会将原本的特殊字符意义去除

*         表示重复0到无穷多个前一个RE(正则表达式)字符

[list]    表示搜索含有list的字符串

[n1-n2]   表示搜索指定的字符串范围,例如[0-9] [a-z] [A-Z]等

[^list]   表示反向字符串的范围,例如[0-9]表示非数字字符,[A-Z]表示非大写字符范围

\{n,m\}   表示找出n到m个前一个RE字符

\{n,\}    表示n个以上的前一个RE字符

egrep总结:

+    表示重复一个或一个以上的前一个RE字符

范例:egrep 'go+d' regular_express.txt

表示搜寻(god)(good)(goood)...等等字符串,o+代表[一个以上的o]

?    表示重复零个或一个的前一个RE字符

范例:egrep 'go?d' regular_express.txt

表示搜寻(gd)(god)字符串,o?代表[空的或1个o]

注:egrep下'go+d'和'go?d'的结果集合就等于grep下的'go*d'

|    表示用或(or)的方式找出数个字符串

范例:egrep 'gd|good|dog' regular_express.txt

表示搜寻(gd)或(god)或(god)字符串,|代表或

()    表示找出群组字符串

范例:egrep 'g(la|oo)d' regular_express.txt

表示搜寻(glad)或(good)字符串

()    +表示找出多个重复群组的判别

范例: echo 'AxyzxyzxyzxyzxyzC'|egrep 'A(xyz)+C'

表示搜寻开头是A结尾是C,中间有一个以上的'xyz'字符串

sed:

插入:

1.将/etc/passwd 的内容列出并打印行号,同时,将2-5行删除显示


复制代码 代码如下:


# nl /etc/passwd | sed '2,5d'


注: sed是sed -e的简写, 后接单引号

同上删除第2行


复制代码 代码如下:


# nl /etc/passwd | sed '2d'


同上删除第三行到最后一行


复制代码 代码如下:


# nl /etc/passwd | sed '3,$d'


2.在第二行后加上一行test


复制代码 代码如下:


# nl /etc/passwd | sed '2a test'


在第二行前加上一行test


复制代码 代码如下:


# nl /etc/passwd | sed '2i test'


在第二行后加入两行test


复制代码 代码如下:


# nl /etc/passwd | sed '2a test \

> test'


替换行:

3.将2-5行内容取代为 No 2-5 number


复制代码 代码如下:


# nl /etc/passwd | sed '2,5c No 2-5 number'


4 列出/etc/passwd 内第5-7行


复制代码 代码如下:


# nl /etc/passwd |sed -n '5,7p'


替换字符串:

sed 's/被替换字符串/新字符串/g'

1.获取本机IP的行


复制代码 代码如下:


# /sbin/ifconfig eth0 |grep 'inet addr'


将IP前面的部分予以删除


复制代码 代码如下:


# /sbin/ifconfig eth0 |grep 'inet addr'| sed 's/^.*addr://g'


将IP后面的部分删除


复制代码 代码如下:


# /sbin/ifconfig eth0 |grep 'inet addr'| sed 's/^.*addr://g'| sed 's/Bcast:.*$//g'

-------------------

192.168.100.74

-------------------


2.用grep将关键词MAN所在行取出来


复制代码 代码如下:


# cat /etc/man.config |grep 'MAN'


删除批注行


复制代码 代码如下:


# cat /etc/man.config |grep 'MAN'| sed 's/^#.*$//g'


删除空白行


复制代码 代码如下:


# cat /etc/man.config |grep 'MAN'| sed 's/^#.*$//g'| sed '/^$/d'


3.利用sed将regular_express.txt内每一行若为.的换成!

注:-i参数会直接修改文本,而并非直接输出


复制代码 代码如下:


# sed -i 's/.*\.$/\!/g' regular_express.txt


4.利用sed在文本最后一行加入 #This is a test

注: $代表最后一行 a代表行后添加


复制代码 代码如下:


# sed -i '$a #This is a test' regular_express.txt


将selinux配置文件enforcing改成disabled


复制代码 代码如下:


# sed -i '6,6c SELINUX=disabled' /etc/selinux/config


延伸正规表示法:


复制代码 代码如下:


# grep -v '^$' regular_express.txt |grep -v '^#'


延伸写法:


复制代码 代码如下:


# egrep -v '^$'|'^#' regular_express.txt


1. +表示重复一个或一个以上的前一个RE字符

例如:egrep -n 'go+d' regular_express.txt

普通写法: grep -n 'goo*d' regular_express.txt

2. ?表示重复零个或一个前一个RE字符

例如: egrep -n 'go?d' regular_express.txt

3. |表示用或的方式找出数个字符串

例如: egrep -n 'gd|good' regular_express.txt

4. ()表示找出群组字符串

例如: egrep -n 'g(la|oo)d' regular_express.txt

也就是搜寻(glad)或good这两个字符串

5. ()+多个重复群组判别

例如: echo 'AxyzxyzxyzxyzC'|egrep 'A(xyz)+C'

也就是要找开头是A结尾是C 中间有一个以上的'xyz'字符串的意思

awk:

1.用last取出登陆数据前五行


复制代码 代码如下:


# last -n 5


取出账号与登陆者IP,且账号与IP之间以TAB隔开


复制代码 代码如下:


# last -n 5 |awk '{print $1 "\t" $3}'


注:$1代表用空格或TAB隔开的第一个字段,以此类推。。

  $0代表该行全部字段


复制代码 代码如下:


# last -n 5 |awk '{print $1 "\t lines:" NR "\t columes:" NF}'


注: NF代表每一行的$0的字段总数

   NR代表目前awk所处的是第几行数据

   FS代表目标分隔符,默认为空格

2.在/etc/passwd中以:来作为分段字符,则我们要查阅第三栏小于10以下的数据,并只列出账号与第三栏


复制代码 代码如下:


# cat /etc/passwd | awk '{FS=":"} $3<10 {print $1 "\t \t"$3}'


注:查询结果未显示第一行数据,是因为我们虽然定义了FS=":" 但却只能在第二行生效

想读取第一行就需要BEGIN这个关键词:


复制代码 代码如下:


# cat /etc/passwd | awk 'BEGIN {FS=":"} $3<10 {print $1 "\t \t"$3}'


df:

比较两个文件的差异:


复制代码 代码如下:


# diff /etc/rc3.d/ /etc/rc5.d/

-------------------

Only in /etc/rc3.d/: K30spice-vdagentd

Only in /etc/rc5.d/: S70spice-vdagentd

-------------------


实例:

1。统计TCP连接状态


复制代码 代码如下:


# netstat -na | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

/^tcp/


过滤出以tcp开头的行,“^”为正则表达式用法,以...开头,这里是过滤出以tcp开头的行。

S[]

定义了一个名叫S的数组,在awk中,数组下标通常从 1 开始,而不是 0。

NF

当前记录里域个数,默认以空格分隔,如上所示的记录,NF域个数等于

$NF

表示一行的最后一个域的值,如上所示的记录,$NF也就是$6,表示第6个字段的值,也就是SYN_RECV或TIME_WAIT等。

S[$NF]

表示数组元素的值,如上所示的记录,就是S[TIME_WAIT]状态的连接数

++S[$NF]

表示把某个数加一,如上所示的记录,就是把S[TIME_WAIT]状态的连接数加一

结果就是显示S数组中最终的数组值

例:S[TIME_WAIT]=最终值 S[TESTABLISHED]=最终值

END

for(key in S)

遍历S[]数组

print key,”\t”,S[key]

打印数组的键和值,中间用\t制表符分割,显示好一些。

 

 

shell脚本学习:正则表达式之sed,tr篇

在linux中,主要通过sed命令来替换文本,通过正则表达式匹配出的命令,可以用sed来灵活的替换掉,极大的节省了工作量。可以说,sed是 shell脚本里替换的最主要力量,也是shell脚本里用的最多的命令之一,sed是基于行的编译器,也就是说,它会将匹配到的内容的行打印出来,而且 sed有自己的模式空间(内存),也就是说sed并不会改变原文件的内容,但是sed -i  可以直接修改原文件(此功能慎用,很容易造成损失)

         sed的用法格式:

         sed [option] /PATTERN/COMMAND files

         sed [option]  ADDR,ADDR/COMMAND files

                 -n    //避免没有被匹配的行显示

                 -i     //直接修改原文件

另外介绍三个基本正则表达式,可以配合sed来匹配单词

           \<或\b     //锚定词首         [^ ]    //取反,除...之外的一个字符

           \>或\b     //锚定词尾

##一个简单的例子来说明sed的用法:

           sed 1,3p /proc/cpuinfo

这条命令将cpuinfo的内容前三行打印两次,如果只要显示前三行,则加 -n 选项,这里的1,3指第一到三行,p是打印的意思。

##扩展几个sed的command:

         p 打印       /i   在匹配的内容之前插入

         /d 删除       /a  在匹配的内容之后插入

         s 替换        /g  全局替换

同时sed也可以使用正则表达式:

例如:

sed "/^model/a\#This is my cpu." /proc/cpuinfo

#看到^了吗?这个命令的意思是在model之后插入#This is my cpu. 注意是model这行后面的一行。

 

下面介绍替换,替换的模式 s/要查找的内容/要替换成的内容/command

例如:

sed  ‘1,$s/yes/YES/' /proc/cpuinfo

#将/proc/cpuinfo里从1到最后一行里的yes替换成YES。

#1,$指从第一行到最后一行 $在这里匹配最后一行,$-2倒数第二行,以此类推。

# 也可以使用/g全局替换,即符合条件的全部替换掉

 

好了,关于sed的几个练习:

sed练习

1、将/etc/inittab文件中以id开头后面跟了两个冒号且两个冒号间有一个数字的那一行中的那两个冒号间的数字改为3;

2、将/etc/passwd文件中以n开头的所有单词的词首字母改为大写;

3、在/proc/meminfo文件中所有以HugePages开头的行后面添加“# For performancing”一个新行;

4、删除/etc/inittab文件中所有以#开头,或者以一些空白字符后跟一个#开头的行,并且将所有以一个空格后跟一个数字结尾的行中的那个行尾的数字改为0;

 

 

 

 

 

答案:1.  sed  s@^id:[0-9]:@id:3:@g /etc/inittab

                #这里的@也是替代符号,当要替换的文本是路径时,这个技巧很好用。

             2.  sed '1,$s/\bn/N/pg' /etc/passwd

             3.   sed "/HugePages/a\# For performancing" /proc/meminfo

             4.   sed -e '/^[[:space:]]*#.*/d' /etc/inittab -e "s/[[:space:]][0-9]$/ 0/g" /etc/inittab

                 #这里使用了-e 选项,处理两条sed命令 因为文本的开头都有一个空字符,所以^[[:space:]]*#匹配第一个要求,*代表0到任意个

————————————————————————————————————————————————————————————————————————————————

        tr命令可以方便的将指定字符替换成别的字符,例如小写字母替换成大写字母,而sed是处理行的,和tr配合使用,可以方便快速的替换行里的字符。

  例如:echo abCD |  tr ’ab‘ ’AB‘  //将ab替换为AB

  tr有一个比较常用的选项 -d, –delete 删除集合1中的字符而不是转换

   eco "banana" | tr -d 'a'

 

#一个sed和tr的脚本

写一个脚本:

1、将/var/目录下所有文件的文件名的首字母和尾字母显示时改为大写;




[cpp]​view plain​​​​copy​


  1. #!/bin/bash  
  2. #: Title:lsvar   
  3. #: Synopsis:   
  4. #: Date:2011-07-26 23:35:27  
  5. #: Version: 1.0  
  6. #: Author: Dean   
  7. #: Options:  
  8.   
  9. for FILE in `ls /var`; do  
  10.       FLITER=`echo "$FILE" | sed '1,$s/[a−zA−Z].*/\1/g' | tr 'a-z' 'A-Z'`  
  11.       LLITER=`echo "$FILE" | sed '1,$s/.*[a−zA−Z]/\1/g' | tr 'a-z' 'A-Z'`  
  12.   
  13.       echo "$FILE" | sed "s/[a-zA-Z].∗[a-zA-Z]/$FLITER\1$LLITER/g"  
  14. done  


 

 

sed, a stream editor



Next: ​​Introduction​​, Up: ​​(dir)​



sed, a stream editor

This file documents version 4.2.1 of GNUsed, a stream editor.

Copyright © 1998, 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.

This document is released under the terms of the GNU Free Documentation License as published by the Free Software Foundation; either version 1.1, or (at your option) any later version.

You should have received a copy of the GNU Free Documentation License along with GNUsed; see the fileCOPYING.DOC. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02110-1301, USA.

There are no Cover Texts and no Invariant Sections; this text, along with its equivalent in the printed manual, constitutes the Title Page.

--- The detailed node listing ---

sed Programs:

Examples:

 

 

​如何在grep,sed等正则表达式中引用使用shell变量​​ 



ps aux|grep ^"$(whoami)"


ps aux|grep ^"$(id -u )"


ps aux|grep ^"$(id -u $(whoami))"


 


其中$(id -u )可以使用`id -u`代替


 

 

 

 


​shell中的正则表达式sed​




本文主要说一些正则的基本语法,并且结合linux的各种小工具(egrep、sed、awk)列举一些使用实例。

 

一、基本语法

正则的基本语法就大概是下面这些,但是正则远不止这些,甚至可以写一本书,当然了,我们这里只列举一些简单的

用法,这些已经可以解决大部分实际问题了。

1、字符类

字符

含义

举例

.

匹配任意一个字符

abc. 可以匹配abcd 、abc9 等

[]

匹配括号中的任意一个字符

[abc]d 可以匹配ad 、bd 或cd

-

用在[]中,表示字符范围

[0-9a-fA-F] 可以匹配一位十六进制数字

^

如果位于[]的开头,则匹配除去括号中字符之外的一切字符

[^xy] 匹配除xy 之外的任一字符,因此[^xy]1 可以匹配a1 、b1 但不匹配x1 、y1

[[:xxx:]]

grep 工具预定义的一些命名字符类

[[:alpha:]] 匹配一个字母,[[:digit:]] 匹配一个数字

2、数量限定符

字符

含义

举例

?

紧跟在它前面的单元匹配零次或一次

[0-9]?/.[0-9] 匹配0.0 、2.3 、.5 等,由于. 在正则表达式中是一个特殊字符,所以需要用/ 转义一下,取字面值

+

紧跟在它前面的单元匹配一次或多次

[a-zA-Z0-9.-_]+@[a-zA-Z0-9.-_]+/.[a-zA-Z0-9.-_]匹配email

*

紧跟在它前面的单元匹配零次或多次

[0-9][0-9]* 匹配至少一位数字,等价于[0-9]+ ,[a-zA-Z_]+[a-zA-Z_0-9]* 匹配C语言的标识符

\{N\}

紧跟在它前面的单元应精确匹配N次

[1-9][0-9]\{2\} 匹配从100 到999 的整数

\{N,\}

紧跟在它前面的单元至少要匹配n次

[1-9][0-9]\{2,\} 匹配三位以上(含三位)的整数

\{,M\}

紧跟在它前面的单元至多匹配m次

[0-9]\{,1\}和[0-9]?意义一样,

\{N,M\}

紧跟在它前面的单元至少匹配n次,至多匹配m次

[0-9]\{1,3\}/.[0-9]\{1,3\}/.[0-9]\{1,3\}/.[0-9]\{1,3\}/.用于匹配ip地址

3、位置限定符


字符

含义

举例

^

匹配行首的位置

^content匹配以content开头的行


$

匹配行末的位置

:$匹配以:结尾的行,^$匹配空行


/<

匹配单词开头的位置

/

 

/>

匹配单词结尾的位置

p/> 匹配leap ... ,但不匹配parent 、sleepy


/b

匹配单词开头或结尾的位置

ap/b匹配leap,/ble匹配leap,/bat/b 匹配... at ... ,但不匹配cat 、atexit 、batch


/B

匹配非单词开头和结尾的位置

/Bat/B 匹配battery ,但不匹配... attend 、hat ...


 

4、其他特殊字符

字符

含义

举例

/

转义字符,普通字符转义为特殊字符,特殊字符转义为普通字符

普通字符< 写成/< 表示单词开头的位置,特殊字符. 写成/. 以及/ 写成// 就当作普通字符来匹配

()

将正则表达式的一部分括起来组成一个单元,可以对整个单元使用数量限定符

([0-9]\{1,3\}/.){3}\[0-9]\{1,3\} 匹配IP地址

|

连接两个表达式,表示或的关系

n[o-either]可以匹配no或neither

 

 

二、小工具

1、grep/egrep

grep 是一种查找过滤工具,正则表达式在grep 中用来查找符合模式的字符串。

egrep相当于grep -E,表示采用Extended正则表达式语法。grep的正则表达式有Basic和 Extended两种规范

上述列举的正则表达式语法都适用于egrep。而grep的语法则相对简陋一些,?+(){}|都只是一些匹配字符了。

 

2、sed

sed意为流编辑器(Stream Editor),在Shell脚本和Makefile中作为过滤器使用非常普遍,也就是把前一个程序的输出引入sed的输入,经过一系列编辑命令转换为另 一种格式输出。sed和vi都源于早期UNIX的ed工具,所以很多sed命令和vi的末行命令是相同的。

 

在正常情况下,sed将待处理的行读入模式空间,脚本中的命令就一条接着一条的对该行进行处理,直到脚本执行完毕,然后该行被输出,模式空间清空;然后重复刚才的动作,文件中的新的一行被读入,直到文件处理完备。

 

看了很多写sed的就属鸟哥写的最好了,摘录一下:




[php]​view plain​​​​copy​​​​print​​​​?​

  1. [root@linux ~]# sed [-nefr] [动作]  
  2. 参数∶  
  3. -n  ∶使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN   
  4.       的资料一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过  
  5.       sed 特殊处理的那一行(或者动作)才会被列出来。  
  6. -e  ∶直接在指令列模式上进行 sed 的动作编辑;  
  7. -f  ∶直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的   
  8.       sed 动作;  
  9. -r  ∶sed 的动作支援的是延伸型正规表示法的语法。(预设是基础正规表示法语法)  
  10. -i  ∶直接修改读取的档案内容,而不是由萤幕输出。  
  11.   
  12. 动作说明∶  [n1[,n2]]function  
  13. n1, n2 ∶不见得会存在,一般代表『选择进行动作的行数』,举例来说,如果我的动作  
  14.          是需要在 10 到 20 行之间进行的,则『 10,20[动作行为] 』  
  15.   
  16. function 有底下这些咚咚∶  
  17. a   ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~  
  18. c   ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!  
  19. d   ∶删除,因为是删除啊,所以 d 后面通常不接任何咚咚;  
  20. i   ∶插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);  
  21. p   ∶列印,亦即将某个选择的资料印出。通常 p 会与参数 sed -n 一起运作~  
  22. s   ∶取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配  
  23.       正规表示法!例如 1,20s/old/new/g 就是啦!  
  24. 范例∶  
  25.   
  26. 范例一∶将 /etc/passwd 的内容列出,并且我需要列印行号,同时,请将第 2~5 行删除!  
  27. [root@linux ~]# nl /etc/passwd | sed '2,5d'  
  28.      1  root:x:0:0:root:/root:/bin/bash  
  29.      6  sync:x:5:0:sync:/sbin:/bin/sync  
  30.      7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown  
  31. .....(后面省略).....  
  32. # 看到了吧?因为 2-5 行给他删除了,所以显示的资料中,就没有 2-5 行棉~  
  33. # 另外,注意一下,原本应该是要下达 sed -e 才对,没有 -e 也行啦!  
  34. # 同时也要注意的是, sed 后面接的动作,请务必以 '' 两个单引号括住喔!  
  35. # 而,如果只要删除第 2 行,可以使用 nl /etc/passwd | sed '2d' 来达成,  
  36. # 至于第 3 到最后一行,则是 nl /etc/passwd | sed '3,$d' 的啦!   
  37.   
  38. 范例二∶承上题,在第二行后(亦即是加在第三行)加上『drink tea?』字样!  
  39. [root@linux ~]# nl /etc/passwd | sed '2a drink tea'  
  40.      1  root:x:0:0:root:/root:/bin/bash  
  41.      2  bin:x:1:1:bin:/bin:/sbin/nologin  
  42. drink tea  
  43.      3  daemon:x:2:2:daemon:/sbin:/sbin/nologin  
  44. # 嘿嘿!在 a 后面加上的字串就已将出现在第二行后面棉!那如果是要在第二行前呢?  
  45. # nl /etc/passwd | sed '2i drink tea' 就对啦!  
  46.   
  47. 范例三∶在第二行后面加入两行字,例如『Drink tea or .....』『drink beer?』  
  48. [root@linux ~]# nl /etc/passwd | sed '2a Drink tea or ....../  
  49. > drink beer ?'  
  50.      1  root:x:0:0:root:/root:/bin/bash  
  51.      2  bin:x:1:1:bin:/bin:/sbin/nologin  
  52. Drink tea or ......  
  53. drink beer ?  
  54.      3  daemon:x:2:2:daemon:/sbin:/sbin/nologin  
  55. # 这个范例的重点是,我们可以新增不只一行喔!可以新增好几行~  
  56. # 但是每一行之间都必须要以反斜线 / 来进行新行的增加喔!所以,上面的例子中,  
  57. # 我们可以发现在第一行的最后面就有 / 存在啦!那是一定要的喔!  
  58.   
  59. 范例四∶我想将第2-5行的内容取代成为『No 2-5 number』呢?  
  60. [root@linux ~]# nl /etc/passwd | sed '2,5c No 2-5 number'  
  61.      1  root:x:0:0:root:/root:/bin/bash  
  62. No 2-5 number  
  63.      6  sync:x:5:0:sync:/sbin:/bin/sync  
  64. # 没有了 2-5 行,嘿嘿嘿嘿!我们要的资料就出现啦!  
  65.   
  66. 范例五∶仅列出第 5-7 行  
  67. [root@linux ~]# nl /etc/passwd | sed -n '5,7p'  
  68.      5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin  
  69.      6  sync:x:5:0:sync:/sbin:/bin/sync  
  70.      7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown  
  71. # 为什么要加 -n 的参数呢?您可以自行下达 sed '5,7p' 就知道了!(5-7行会重复输出)  
  72. # 有没有加上 -n 的参数时,输出的资料可是差很多的喔!  
  73.   
  74. 范例六∶我们可以使用 ifconfig 来列出 IP ,若仅要 eth0 的 IP 时?  
  75. [root@linux ~]# ifconfig eth0  
  76. eth0      Link encap:Ethernet  HWaddr 00:51:FD:52:9A:CA  
  77.           inet addr:192.168.1.12  Bcast:192.168.1.255  Mask:255.255.255.0  
  78.           inet6 addr: fe80::250:fcff:fe22:9acb/64 Scope:Link  
  79.           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1  
  80. .....(以下省略).....  
  81. # 其实,我们要的只是那个 inet addr:..那一行而已,所以棉,利用 grep 与 sed 来捉  
  82. [root@linux ~]# ifconfig eth0 | grep 'inet ' | sed 's/^.*addr://g' | /  
  83. > sed 's/Bcast.*$//g'  
  84. # 您可以将每个管线 (|) 的过程都分开来执行,就会晓得原因棉!  
  85. # 去头去尾之后,就会得到我们所需要的 IP 亦即是 192.168.1.12 棉~  
  86.   
  87. 范例七∶将 /etc/man.config 档案的内容中,有 MAN 的设定就取出来,但不要说明内容。  
  88. [root@linux ~]# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g' | /  
  89. > sed '/^$/d'  
  90. # 每一行当中,若有 # 表示该行为注解,但是要注意的是,有时候,  
  91. # 注解并不是写在第一个字元,亦即是写在某个指令后方,如底下的模样∶  
  92. # 『shutdown -h now # 这个是关机的指令』,注解 # 就在指令的后方了。  
  93. # 因此,我们才会使用到将 #.*$ 这个正规表示法!  
  94.   
  95. 范例八∶利用 sed 直接在 ~/.bashrc 最后一行加入『# This is a test』  
  96. [root@linux ~]# sed -i '$a # This is a test'  ~/.bashrc  
  97. # 上头的 -i 参数可以让你的 sed 直接去修改后面接的档案内容喔!而不是由萤幕输出。  
  98. # 至于那个 $a  则代表最后一行才新增的意思。  

不过鸟哥的不是很全,特补充如下:



  • n和p一起使用:$ sed -n 's/^test/mytest/p'
    example
    (-n)选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的test被替换成mytest,就打印

    它。
  • 引用:$ sed 's/^192.168.0.1/&localhost/' example-----&符号表示替换换字符串中被找到的部份。所有以192.168.0.1开头的行都会被替换成它自已加 localhost,变成192.168.0.1localhost。
  • 引用:$ sed -n 's//(love/)able//1rs/p' example-----love被标记为1,所有loveable会被替换成lovers,而且替换的行会被打印出来。
  • 分隔符:$ sed 's#10#100#g' example-----不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。
  • 用正则表示范围:$ sed -n '/test/,/check/p' example-----所有在模板test和check所确定的范围内的行都被打印。
  • 正则和数字混用表示范围:$ sed -n '5,/^test/p' example-----打印从第五行开始到第一个包含以test开始的行之间的所有行。
  • $ sed '/test/,/check/s/$/sed test/' example-----对于模板test和west之间的行,每行的末尾用字符串sed test替换。
  • 一次执行多条命令:$ sed -e '1,5d' -e 's/test/check/' example-----(-e)选项允许在同一行里执行多条命令。如例子所示,第一条命令删除1至5行,第二条命令用check替换test。命令的执 行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。
  • 并不常用的一种用法:$ sed '/test/{ n; s/aa/bb/; }' example-----如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。
  • h命令和G命令: $ sed -e '/test/h' -e '$G‘ example-----在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将 打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保 持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中 的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。
  • 特殊字符"^"和"$"匹配的是模式空间的最开始与最末尾
  • n: 将模式空间中的内容输出,然后把下一行读入模式空间
  • sed '/test/{a;b;c}' 这个用法可以针对匹配test的行执行a、b、c这三天命令。

补充几个除d、a、i、s、c、p之外不常用的命令:



  • h:拷贝模板块的内容到内存中的缓冲区。
  • H:追加模板块的内容到内存中的缓冲区
  • g:获得内存缓冲区的内容,并替代当前模板块中的文本。
  • G:获得内存缓冲区的内容,并追加到当前模板块文本的后面。sed G可以在每一行后面添加一个空白行,这是因为当前内存缓冲区为空,每次都把缓冲区的空内容添加到了每一行后面。
  • sed '/^$/d;G':用分号分隔多条命令,每一条命令都会作用在当前行上。

更多用法可以参考:

http://sed.sourceforge.net/sed1line_zh-CN.html

http://blog.chinaunix.net/u2/89923/showart_2206200.html

http://www.tsnc.edu.cn/default/tsnc_wgrj/doc/sed.htm

 

 

 



如何用Sed和正则表达式提取子字符串


现在有如下一串字符串:


    "asdfkjasldjkf"shiner"df


 


需求:


     需要提取出shiner子字符串。


 


命令如下:


[root@localhost /]$  echo "asdfkjasldjkf\"shiner\"df" | sed 's/\(.*\)"\(.*\)"\(.*\)/\2/g'

shiner


命令解释


s: 表示替换命令


\(.*\)" : 表示第一个引号前的内容


"\(.*\)":表示两引号之间的内容


)"\(.*\):表示引号后的内容


\2: 表示第二对括号里面的内容


括号里的表达式匹配的内容,可以用\1,\2等进行引用,第n个括号对内的内容,就用\n引用。


 


这个命令的意思是:


用\2代表的第二个括号的内容(shiner)去替换整个字符串,这样就得到了我们所需要的子字符串了。


 


 


 


 


 



​ Sed 命令详解 正则表达式元字符 ​


分类: ​​shell​​ 2013-01-10 10:07 7549人阅读 ​​评论​​(0) 收藏 ​​举报​



1.简介


sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。


sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程如下:首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后 处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后 一行后,sed便结束运行。sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。


 


 


 


 


 


2.定址


定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。


 


地址是一个数字,则表示行号;是“$"符号,则表示最后一行。例如: 


 


 



​sed -n '3p' datafile
只打印第三行​



 

 只显示指定行范围的文件内容,例如:



# 只查看文件的第100行到第200行

sed -n '100,200p' mysql_slow_query.log


 

地址是逗号分隔的,那么需要处理的地址是这两行之间的范围(包括这两行在内)。范围可以用数字、正则表达式、或二者的组合表示。例如:



​sed '2,5d' datafile
#删除第二到第五行
sed '/My/,/You/d' datafile
#删除包含"My"的行到包含"You"的行之间的行
sed '/My/,10d' datafile
#删除包含"My"的行到第十行的内容​



 


 

 

3.命令与选项

sed命令告诉sed如何处理由地址指定的各输入行,如果没有指定地址则处理所有的输入行。

 

3.1 sed命令


 命令

 功能

 a\


 在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行


 c\

 用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用"\"续行

 i\

 在当前行之前插入文本。多行时除最后一行外,每行末尾需用"\"续行

 d

 删除行

 h

 把模式空间里的内容复制到暂存缓冲区

 H

 把模式空间里的内容追加到暂存缓冲区

 g

 把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容

 G

 把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面

 l

 列出非打印字符

 p

 打印行

 n

 读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理

 q

 结束或退出sed

 r

 从文件中读取输入行

 !

 对所选行以外的所有行应用命令

 s

 用一个字符串替换另一个

 g

 在行内进行全局替换

 

 

 w

 将所选的行写入文件

 x

 交换暂存缓冲区与模式空间的内容

 y

 将字符替换为另一字符(不能对正则表达式使用y命令)


 

3.2 sed选项


 选项

 功能

 -e

 进行多项编辑,即对输入行应用多条sed命令时使用

 -n

 取消默认的输出

 -f

 指定sed脚本的文件名


 


 


 


 


4.退出状态


sed不向grep一样,不管是否找到指定的模式,它的退出状态都是0。只有当命令存在语法错误时,sed的退出状态才不是0。


 


 


 



5.正则表达式元字符


 与grep一样,sed也支持特殊元字符,来进行模式查找、替换。不同的是,sed使用的正则表达式是括在斜杠线"/"之间的模式。


如果要把正则表达式分隔符"/"改为另一个字符,比如o,只要在这个字符前加一个反斜线,在字符后跟上正则表达式,再跟上这个字符即可。例如:sed -n '\o^Myop' datafile


 


 元字符

 功能

 示例

 ^

 行首定位符

 /^my/  匹配所有以my开头的行

 $

 行尾定位符

 /my$/  匹配所有以my结尾的行

 .

 匹配除换行符以外的单个字符

 /m..y/  匹配包含字母m,后跟两个任意字符,再跟字母y的行

 *

 匹配零个或多个前导字符

 /my*/  匹配包含字母m,后跟零个或多个y字母的行

 []

 匹配指定字符组内的任一字符

 /[Mm]y/  匹配包含My或my的行

 [^]

 匹配不在指定字符组内的任一字符

 /[^Mm]y/  匹配包含y,但y之前的那个字符不是M或m的行

 ..

 保存已匹配的字符

 1,20s/youself/\1r/  标记元字符之间的模式,并将其保存为标签1,之后可以使用\1来引用它。最多可以定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,如果发现youself,则替换为your。

 &

 保存查找串以便在替换串中引用

 s/my/**&**/  符号&代表查找串。my将被替换为**my**

 \<

 词首定位符

 /\<my/  匹配包含以my开头的单词的行

 \>

 词尾定位符

 /my\>/  匹配包含以my结尾的单词的行

 x\{m\}

 连续m个x

 /9\{5\}/ 匹配包含连续5个9的行

 x\{m,\}

 至少m个x

 /9\{5,\}/  匹配包含至少连续5个9的行

 x\{m,n\}

 至少m个,但不超过n个x

 /9\{5,7\}/  匹配包含连续5到7个9的行


 


6.范例


 


6.1 p命令


命令p用于显示模式空间的内容。默认情况下,sed把输入行打印在屏幕上,选项-n用于取消默认的打印操作。当选项-n和命令p同时出现时,sed可打印选定的内容。


 



​sed '/my/p' datafile
#默认情况下,sed把所有输入行都打印在标准输出上。如果某行匹配模式my,p命令将把该行另外打印一遍。​


sed -n '/my/p' datafile
#选项-n取消sed默认的打印,p命令把匹配模式my的行打印一遍。


 

6.2 d命令

命令d用于删除输入行。sed先将输入行从文件复制到模式空间里,然后对该行执行sed命令,最后将模式空间里的内容显示在屏幕上。如果发出的是命令d,当前模式空间里的输入行会被删除,不被显示。


​sed '$d' datafile
#删除最后一行,其余的都被显示

sed '/my/d' datafile
#删除包含my的行,其余的都被显示​


 

6.3 s命令


​sed 's/^My/You/g' datafile
#命令末端的g表示在行内进行全局替换,也就是说如果某行出现多个My,所有的My都被替换为You。

sed -n '1,20s/My$/You/gp' datafile
#取消默认输出,处理1到20行里匹配以My结尾的行,把行内所有的My替换为You,并打印到屏幕上。​



  



​sed 's#My#Your#g' datafile
#紧跟在s命令后的字符就是查找串和替换串之间的分隔符。分隔符默认为正斜杠,但可以改变。无论什么字符(换行符、反斜线除外),只要紧跟s命令,就成了新的串分隔符。​


 

6.4 e选项

-e是编辑命令,用于sed执行多个编辑任务的情况下。在下一行开始编辑前,所有的编辑动作将应用到模式缓冲区中的行上。


​sed -e '1,10d' -e 's/My/Your/g' datafile​

​#选项-e用于进行多重编辑。第一重编辑删除第1-3行。第二重编辑将出现的所有My替换为Your。因为是逐行进行这两项编辑(即这两个命令都在模式空间的当前行上执行),所以编辑命令的顺序会影响结果。​


 

6.5 r命令

r命令是读命令。sed使用该命令将一个文本文件中的内容加到当前文件的特定位置上。


​sed '/My/r introduce.txt' datafile
#如果在文件datafile的某一行匹配到模式My,就在该行后读入文件introduce.txt的内容。如果出现My的行不止一行,则在出现My的各行后都读入introduce.txt文件的内容。​



 


6.6 w命令



​sed -n '/hrwang/w me.txt' datafile


 

6.7 a\ 命令

a\ 命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面。所追加的文本行位于sed命令的下方另起一行。如果要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外。最后一行将以引号和文件名结束。


​sed '/^hrwang/a\
>hrwang and mjfan are husband\
>and wife' datafile
#如果在datafile文件中发现匹配以hrwang开头的行,则在该行下面追加hrwang and mjfan are husband and wife​


 

6.8 i\ 命令

i\ 命令是在当前行的前面插入新的文本。

 

6.9 c\ 命令

sed使用该命令将已有文本修改成新的文本。

 

6.10 n命令

sed使用该命令获取输入文件的下一行,并将其读入到模式缓冲区中,任何sed命令都将应用到匹配行紧接着的下一行上。


​sed '/hrwang/{n;s/My/Your/;}' datafile



注:如果需要使用多条命令,或者需要在某个地址范围内嵌套地址,就必须用花括号将命令括起来,每行只写一条命令,或这用分号分割同一行中的多条命令。


 


6.11 y命令


该命令与UNIX/Linux中的tr命令类似,字符按照一对一的方式从左到右进行转换。例如,y/abc/ABC/将把所有小写的a转换成A,小写的b转换成B,小写的c转换成C。


 



​sed '1,20y/hrwang12/HRWANG^$/' datafile
#将1到20行内,所有的小写hrwang转换成大写,将1转换成^,将2转换成$。
#正则表达式元字符对y命令不起作用。与s命令的分隔符一样,斜线可以被替换成其它的字符。​


 

6.12 q命令

q命令将导致sed程序退出,不再进行其它的处理。


​sed '/hrwang/{s/hrwang/HRWANG/;q;}' datafile


 

6.13 h命令和g命令


​#cat datafile​

​My name is hrwang.​

​Your name is mjfan.​

​hrwang is mjfan's husband.​

​mjfan is hrwang's wife.​

 

​sed -e '/hrwang/h' -e '$G' datafile​

​sed -e '/hrwang/H' -e '$G' datafile​

​#通过上面两条命令,你会发现h会把原来暂存缓冲区的内容清除,只保存最近一次执行h时保存进去的模式空间的内容。而H命令则把每次匹配hrwnag的行都追加保存在暂存缓冲区。

​sed -e '/hrwang/H' -e '$g' datafile​

​sed -e '/hrwang/H' -e '$G' datafile​

​#通过上面两条命令,你会发现g把暂存缓冲区中的内容替换掉了模式空间中当前行的内容,此处即替换了最后一行。而G命令则把暂存缓冲区的内容追加到了模式空间的当前行后。此处即追加到了末尾。​


 

 

7. sed脚本

sed脚本就是写在文件中的一列sed命令。脚本中,要求命令的末尾不能有任何多余的空格或文本。如果在一行中有多个命令,要用分号分隔。执行脚本时,sed先将输入文 件中第一行复制到模式缓冲区,然后对其执行脚本中所有的命令。每一行处理完毕后,sed再复制文件中下一行到模式缓冲区,对其执行脚本中所有命令。使用 sed脚本时,不再用引号来确保sed命令不被shell解释。例如sed脚本script:


​#handle datafile
3i\
~~~~~~~~~~~~~~~~~~~~~
3,$s/\(hrwang\) is​
​​​ \(mjfan\)/\2 is \1/​​​
$a\
We will love eachother forever!!​

 

 


​#sed -f script datafile
My name is hrwang
Your name is mjfan
~~~~~~~~~~~~~~~~~~~~~
mjfan is hrwang's husband.          #啦啦~~~
mjfan is hrwang's wife.
We will love eachother forever!!​


转自:​​http://blog.chinaunix.net/u/22677/showart_1076318.html​

 


 


 


 


 



​sed正则表达式​

1 正则表达式简介

正则表达式(Regular Expression) 是一种描述文本(或字符串)模式的工具。正则表达式常用于查找文本的场合。想想一下我们日常生活中的例子,假如你想从电话本里找一个联系人的电话,而你又 想不起联系人名字的准确拼法,你可以把电话本从头到尾翻一遍,如果电话本里联系人少的话也许并不是什么麻烦事,但想象一下如果这是记录着公司所有员工的电 话本,你面临的工作便复杂得多了,有可能是从几百甚至几千条记录中寻找你想要的那条电话记录!而利用正则表达式则为解决这一问题提供了一种简便有效的方 法。


正则表达式是一种描述具有某些共同特征的文本的文本,在不同的环境里有不同的格式,但其大致格式是相似的。本文将介绍Unix系统下的正则表达式。


其实,也许在你不清楚正则表达式是什么的时候你已经开始使用它了。想想Linux里一个最常用的命令:


ls *.tar


在这个命令里,*.tar 便是一个正则表达式,它是一个描述了这样的字符串的字符串:以任意数量的任意字符开头(*),后面紧接一个句点(.),然后再跟一个tar(这是在Unix Shell里表示的意思,在其他场合有不同的意思,后文将介绍)。星号(*)我们在DOS里常称之为“通配符(wildcard)”,而在正则表达式里我们称之为“元字符(metacharacter)”。下一章节我们将介绍正则表达式里常用的元字符。


 


2 正则表达式元字符和格式



在上一节里我们用一个例子介绍了什么是正则表达式的“元字符”。其实,元字符是一个或一组代替个或多个字符的字符。听起来有点拗口,但举一个例子也许你就明白了:元字符*用来匹配一个或多个的前一字符;而元字符 用来匹配一个任意的一个字符。正则表达式也可以不使用任何的元字符,一个简单的字符串 /piano/ (在Unix里正则表达式通常用一对斜线作为分隔符,后文在“正则表达式格式”部分中有介绍)也是一个正则表达式,只不过是准确匹配罢了。


下面列出了常用的正则表达式元字符,下一节将以实例的形式逐个介绍这些元字符的用法。需要注意的是,这些元字符并不是在所有的Unix (或Linux) 工具中都可以用,至于某个应用程序支持哪些元字符,可以参照该工具的用户手册。


 


表2.1 正则表达式元字符


 



元字符



功能



示例



匹配结果



^



行首定位符



/^supinfo/



匹配所有以supinfo开头的行


 



$



行尾定位符



/supinfo$/



匹配所有以supinfo结尾的行


 



\<



词首定位符



/\<supinfo/



匹配出现以supinfo为开头的词的行


 



\>



词尾定位符



/supinfo\>/



匹配出现以supinfo为结尾的词的行


 



.



匹配一个字符



/sufo/



包含su,后面紧跟三个任意字符,然后紧跟着fo的行


 



*



匹配0个或多个前一字符



/_*supinfo/



supinfo前有0个或多个下划线的行


 



[]



匹配一组字符里的任意字符


 



/[Ss]pinfo/



包含Supinfo或supinfo的行



[x-y]



匹配指定范围内的字符



/[A-Z0-9]supinfo/



supinfo之前有一个A到Z或0到9的字符


 



[^ ]



匹配不在指定范围内的字符



/[^A-Z0-9]supinfo/



supinfo之前有一个既不是A到Z又不是0到9的字符


 



x\{m\}


x\{m,\}


x\{mn\}



根据字符x出现的次数匹配:


m次;大于等于m次;大于等于m次但小于等于n次


 



/s\{2,5\}/



匹配有2到5个连续出现的s的行



\



转义元字符



/supinfo\. /



匹配包含supinfo,然后后面紧跟一个句点的行(没有 的时候是匹配一个字符)


 



\(\)



创建一个字符标签



/(SUPINFO):use\1NE/



括号中的字符被保存在标号为1的标签里,以后可以用\1来引用。标签编号从左到右依次为1,2,3……最多可以有9个标签。这个例子查找的是SUPINFO:后面跟着一个 use SUPINFONE的字符串



 


还有一点问题需要在这里提出,正则表达式有很多版本——至少存在两个版本:基本正则表达式和扩展正则表达式。在基本正则表达式中,原字符 | ,+ 和 ? 是不允许使用的。并且在使用含有圆括号和花括号的正则表达式时,圆括号和花括号都要用反斜线转义。在书写正则表达式时,比较好的做法是先写出整个正则表达式,然后再用反斜线将需要转义的字符转义。


正则表达式的格式


在Unix 中,正则表达式是被包含在一对斜线中的,斜线之间包含要匹配的字符(模式)。下面是几个例子:


/piano/ /[Pp]iano/            /*pinfo/               /s\{2,5\}oho/



3 正则表达式实例解析

下面我们就以具体的实例来看一下如何使用正则表达式。其中用黑体着重标出的是匹配到的字符串。

一个最简单的例子便是 /all/,比如下面一段文字:

John’s ball fell into the hole

John cried because it is all his life.

 

这个正则表达式不含任何的原字符,它查找的是字符串all,这个字符串all可以是独成一个单词,也可以是其它单词的一部分,因此正则表达式/all/既匹配ball里的all,也匹配完整的单词all。

下面我们着重讨论正则表达式里原字符的用法。

 

3.1            行首、行尾定位符

行首定位符^

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/^Bobby/

匹配位于行首的Bobby。

 

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/Bobby$/

匹配位于行尾的Bobby。

 

3.2            词首、词尾定位符

词首定位符 \<

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/\

匹配位于词首的字符串Bo。

 

词尾定位符 \>

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby

Bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/ball\>/

匹配位于词尾的字符串ball。

 

在一个表达式中搭配使用词首定位符与词尾定位符

John’s ball fell into the hole

John cried because it is his whole life

/\/

匹配以h作为单词开头并且以e作为单词结尾的模式hole。也就是说,字母h的前面是一个分隔单词的字符(比如空格或换行符),字母l的后面也是一个分隔单词的字符。这样,在这个例子中只有完整的单词hole会被匹配,而单词whole就不会被匹配。

 

3.3            匹配单个字符

匹配任意的一个字符 .

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/By/

匹配B开头后面紧跟三个任意字符,最后紧接着一个y的字符串。在这个例子中,Bobby和Bippy都会被匹配。

 

匹配0个或多个前一字符 *

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck balll

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/ al*/

这里的星号(*)匹配0个或多个在它前面的那个字符。前面曾提到过,正则表达式里的*和shell里的*作用是截然不同的。在shell里*表示任意个数的任意字符,而在正则表达式里,*只代表任意个数(包括0个)的前一字符,*可以看作和它前面那个字符是粘连在一起的,*只限制它前面那一个字符。这个正则表达式中的*匹配单独一个或多个连续的l,甚至也匹配一个l也没有的模式,所以,单个字符a也会被匹配。

 

3.4            匹配多个字符

匹配一组字符里的任意字符 [ ]

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck balll

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/[bw]all/

方括号匹配一组字符中的一个,这个正则表达式查找的是第一个字母是b或w,后面紧跟着all的字符串,因此在这个例子中,wall和ball都会被匹配。

 

匹配指定范围内的字符 [x-y]

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/B[a-z]p/

方括号里的短线(-)匹配某一范围内的一个字符,这个正则表达式将查找第一个字母是B,第二个字母是ASCII码介于a到z的字符(小写字母),第三个字母是p的字符串。

 

匹配不在指定范围内的字符 [^ ]

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/all[^A-Z0-9]/

方括号内的脱字符^是一个否定字符,这个正则表达式查找的是后面带一个特殊字符的all,这个特殊字符既不是小写字母又不是大写字母,也不是0到9的数字,比如它可以是一个标点符号或空格。

 

根据字符x出现的次数匹配 x\{m\}  x\{m,\}  x\{m, n\}

比如这个正则表达式:/Go\{2,5\}gle/将匹配G后面至少出现2个,最多有不超过5个o的模式。Google,Goooogle会被匹配,而Gogle和Goooooogle则不会被匹配。

 

3.5            转义字符

如果要匹配的字符串中含有正则表达式的原字符,需要用斜线将其转义,就像c语言里打印单引号 ’ 要写成 \’ 一样。这里有个例子:我们想要查找字符串google.com,要查找的字符串里含有正则表达式的原字符“.”,因此这个正则表达式要写成 /google\.com/,如果不用 \转义,找到的将是google后面跟一个任意的字符,然后跟一个com的字符串。这显然不一定是我们要找的。

 

3.6            字符标签

例如在下面一段文字里:

Occurence and happening are the most general. I mean, the words occurence and happening are most generally used.

在这段文字里有两个拼错的单词,Occurence和occurence,(其实应该是occurrence),我们可以在vi中用下面的表达式将其修改:

 

:1,$s/\([Oo]ccur\)ence/\1rence/

 

我们且不管这个vi命令的用法(其实它是一个替换命令,我们在后面介绍sed时还将提到)我们先拿出这个语句中的两个表达式:

 

/\([Oo]ccur\)ence/

\1rence

 

其中前一个是一个正则表达式。这个命令用后面的表达式内容替换前面的正则表达式匹配到的内容。vi编辑器将查找单词Occurence和occurence,如果找到,就把圆括号中的内容加上标签(Occur或occur被加上标签),因为这是第一个被标记的模式,所以被称为标签1。这个模式被保存在称为寄存器1的内存寄存器中。在第二个正则表达式中用\1引用寄存器1中的内容,\1被替换为寄存器中的内容,后面紧跟一个rence,于是,拼错的Occurence和occurence被改正为正确的Occurrence和occurrence。

 

3.7            原字符组合使用的例子

 

例1:/\/

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/\/

匹配以Bob开头,后面跟任意个数的任意字符,然后以all结尾的字符串。这里再次重复, *在Shell里表示任意个数的任意字符,而在正则表达式里表示任意个数的前一字符。与 配合使用表示任意个数(包括零个)的任意字符。实际上,* 也可以表示重复零次或任意次它前面的一组字符,我们称这一组(有时也可能是一个)字符为“原子”。当原子包括多个字符时,这多个字符要用圆括号括起来,并且需要将圆括号转义;当原子只含一个字符时,可以不用圆括号。在这个例子里,表示一个任意字符,紧跟着一个*表示重复0次或任意次前面的那个任意字符。而下面的例子

/\(sup\)*info/

则表示匹配在字符串info前有0个或多个sup的字符串,因此 supinfo, info, supsupinfo都会被匹配。

 

例2:/B[a-z][bp]*y$/

Here is a tongue twister:

Bobby Bippy bought a bat.

Bobby Bippy bought a ball.

With his bat Bob banged the ball

Banged it bump against the wall

But so boldly Bobby banged it

That he burst his rubber ball, "Boo!" cried Bobby

Bad luck ball, Bad luck Bobby, bad luck ball

Now to drown his many troubles

Bobby Bippy's blowing bubbles.

/B[a-z][bp]*y$/

这个正则表达式匹配这样的字符串:开头字符是B,第二个字母是一个小写字母,后面紧跟0个或多个重复的b或p,最后跟一个y,并且这个字符串位于行的末尾。

 

 

4 sed原理及sed命令格式

4.1            Sed工作原理

 

sed是一个非交互式的流编辑器。所谓非交互式,是指使用sed只能在命令行下输入编辑命令来编辑文本,然后在屏幕上查看输出;而所谓流编辑器,是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕(除非取消了屏幕输出又没有显式地使用打印命令),接着读入下一行。整个文件像流水一样被逐行处理然后逐行输出。

 

下面我们看一下sed的工作过程。

 

sed不是在原输入上直接进行处理的,而是先将读入的行放到缓冲区中,对缓冲区里的内容进行处理,处理完毕后也不会写回原文件(除非用shell的输出重定向来保存结果),而是直接输出到屏幕上。sed运行过程中维护着两个缓冲区,一个是活动的“模式空间(pattern space)”,另一个是起辅助作用的“暂存缓冲区(holding space)”。一般情况下,每当运行sed,sed首先把第一行装入模式空间,进行处理后输出到屏幕,然后将第二行装入模式空间替换掉模式空间里原来的内容,然后进行处理,以此类推。

 

 

 

一般情况下暂存缓冲区是用不到的,但有特殊的命令可以在模式空间与暂存缓冲区之间交换数据,后文将有介绍。由于sed对文本的所有操作都是在缓冲区里进行的,所以不会对原文件造成任何破坏。

 

4.2            Sed命令格式

 

sed的命令格式如下:

 

sed [-Options] [‘Commands’] filename

 

其中,Command是一个sed命令,sed命令一定要被包含在一对单引号中,以免被shell解释,其格式如下:

 

[address-range][sed-command]或

[Pattern-to-match][sed-command]

 

address-range是指要处理的行的范围,又叫地址范围;pattern-to-match是一个要匹配的模式,是一个正则表达式,sed-command是一个sed命令,用来对指定的行进行处理。下面是一个简单的例子:

 

sed –n ‘1,3p’ students

 

这个命令将文件students中的第1到3行打印到屏幕。注意,地址范围和sed命令之间没有空格,如果加入空格,sed也会将其忽略。参数-n用来取消默认输出。默认情况下,sed每读入一行到模式空间,无论是否对其进行处理,在读入下一行之前多要将模式空间中的内容输出到屏幕上。参数-n可以用来取消这种默认的输出,只有当用户用命令p时才将指定的行输出到屏幕。如果没有用参数-n而又对指定行执行了p命令,那么这些行将会被打印两次。

 

地址范围可以是一个数字,这个数字代表了一个行号;也可以是一个用逗号分隔的两个数字表示的范围(包括这两行)。范围可以是数字,正则表达式,或是两者的组合。

 

pattern-to-match是一个要匹配的模式,sed将会对所有匹配的行执行sed-command。其实,这里的pattern-to-match也可以看作是一个地址,这个地址是所有与指定模式匹配的行的行号。因此sed的格式可以归纳为一种:

 

sed [-Options] ‘[address-range][sed-command]’ filename

 

 

 

5 sed命令与选项

5.1            Sed命令

 

常用的sed命令如下表所列:


命令



功能



a\



在当前行之后插入一行或多行

 



c\



用新文本替换当前行中的文本,并开始新的一轮sed命令的执行

 



d



删除行

 



i\



在当前行之前插入文本

 



h



将模式空间里的内容拷贝到暂存缓冲区并替换原来暂存缓冲区的内容

 



H



将模式空间里的内容追加到暂存缓冲区

 



g



将里暂存缓冲区的内容拷贝到模式空间并替换原来模式空间的内容

 



G



将暂存缓冲区里的内容追加到模式空间

 



p



打印模式空间的内容

 



n



读入下一行到模式空间,并接着从下一条命令开始执行

 



q



直接退出sed,不继续执行其后的命令

 



r



读入指定文件的内容

 



w



将行写入文件

 



!



对所选行以外的行进行处理

 



s/regexp/replacement/flag



用replacement替换模式空间由regexp匹配到的内容

 



x



交换模式空间与暂存缓冲区的内容

 



y/source-chars/dest-chars/



将source-chars的字符换成对应的的dest-chars中的字符,source-chars和dest-chars中的字符个数要相同。source-chars和dest-chars中都不能有正则表达式。

 



=



打印当前行的行号,行号是令起一行打印的

 



#



sed脚本文件中领起注释


 

替换命令s/regexp/replacement/flag 中的flag:


flag



功能



g



进行全局替换。不使用此选项将只对该行匹配到的第一个结果进行替换



p



打印模式空间中的内容(替换之后的内容)



filename



将替换之后的内容写入文件filename


 

在后面的章节“sed实例解析”中我们将以实例的形式详细介绍各个命令的用法。


 


 


 


 


 

sed不支持\d。