Linux下正则表达式的应用

正则表达式:

在计算机科学中,正则表达式是这样解释的:它是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在很多文本编辑器或其他工具里,正则表达式通常被用来检索和/或替换那些符合某个模式的文本内容。许多程序设计语言都支持利用正则表达式进行字符串操作。对于系统管理员来讲,正则表达式贯穿在日常运维工作中,无论是查找某个文档,抑或查询某个日志文件分析其内容,都会用到正则表达式。

在linux中,用到正则表达的常用工具有:grep,sed,awk等。

grep/egrep:

grep (缩写来自Globally search a Regular Expression and Print)是一种强大的文本搜索工具,它能使用特定模式匹配(包括正则表达式)搜索文本,并默认输出匹配行。

语法: grep [-cinvABC] 'word' filename

-c(count) :打印符合要求的行数

-i (ignore-case):忽略大小写

-n (line-number):在输出符合要求的行的同时连同行号一起输出

-v (invert-natch):打印不符合要求的行

-A (after-context):后跟一个数字(有无空格都可以),例如 –A2则表示打印符合要求的行以及下面两行

-B (before-context):后跟一个数字,例如 –B2 则表示打印符合要求的行以及上面两行

-C (context):后跟一个数字,例如 –C2 则表示打印符合要求的行以及上下各两行

grep应用示例:

(1)过滤出带有某个关键词的行并输入行号。

1
2
3
[root@localhost ~]# grep -n 'root' /etc/passwd
1:root:x:0:0:usr:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin

(2)过滤不带有某个关键词的行,并输出行号。

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# grep -nv 'nologin' /etc/passwd
1:root:x:0:0:usr:/root:/bin/bash
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
20:hadoop:x:1000:1000:Hadoop:/home/hadoop:/bin/bash
44:cao:x:1001:1001::/home/cao:/bin/bash
45:usr:x:1002:1002:用户,offic,1234567,123:/home/usr:/bin/bash
46:test:x:1003:1003::/home/test:/bin/bash
47:test1:x:1004:1003::/home/test1:/bin/bash

(3)过滤出所有包含数字的行:

1
2
3
[root@localhost ~]# grep '[0-9]' /etc/inittab
# multi-user.target: analogous to runlevel 3
# graphical.target: analogous to runlevel 5

(4)过滤出所有不包含数字的行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost ~]# grep -v '[0-9]' /etc/inittab
# inittab is no longer used when using systemd.
#
# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
#
# systemd uses 'targets' instead of runlevels. By default, there are two main targets:
#
#
# To view current default target, run:
# systemctl get-default
#
# To set a default target, run:
# systemctl set-default TARGET.target
#

(5)把所有以‘#’开头的行去除:

1
2
[root@localhost ~]# grep -v '#' /etc/inittab 
[root@localhost ~]

(6)去除所有空行和以“#”开头的行:

1
2
3
4
[root@localhost ~]# grep -v '#'  /etc/crontab | grep -v '^$'
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

在正则表达式中, “^” 表示行的开始, “\$ ” 表示行的结尾,那么空行则可以用 “^$” 表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost ~]# cat test.txt 
123
abc
456

abc123

#adff

23##

#打印不以字母开头的行
[root@localhost ~]# grep '^[^a-zA-Z]' test.txt
123
456
#adff
23##
#打印以字母开头的行
[root@localhost ~]# grep '^[a-zA-Z]' test.txt
abc
abc123

‘[ ]’ 的应用,如果是数字的话就用[0-9]这样的形式,当然有时候也可以用这样的形式[15]即只含有1或者5,注意,它不会认为是15。如果要过滤出数字以及大小写字母则要这样写[0-9a-zA-Z]。另外[ ]还有一种形式,就是[^字符] 表示除[ ]内的字符之外的字符。

(7)过滤任意一个字符与重复的字符:

1
2
3
4
5
6
7
[root@localhost ~]# grep 'r..o' /etc/passwd
operator:x:11:0:operator:/root:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
geoclue:x:997:995:User for geoclue:/var/lib/geoclue:/sbin/nologin
unbound:x:994:990:Unbound DNS resolver:/etc/unbound:/sbin/nologin
colord:x:992:988:User for colord:/var/lib/colord:/sbin/nologin
sssd:x:991:985:User for sssd:/:/sbin/nologin

. 表示任意一个字符,上例中,就是把符合r与o之间有两个任意字符的行过滤出来, * 表示零个或多个前面的字符。

1
2
3
4
5
6
7
8
[root@localhost ~]# grep  'ooo*' /etc/passwd
root:x:0:0:usr:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
hadoop:x:1000:1000:Hadoop:/home/hadoop:/bin/bash
setroubleshoot:x:990:984::/var/lib/setroubleshoot:/sbin/nologin

‘ooo*’ 表示oo, ooo, oooo … 或者更多的 ‘o’

‘.*’ 表示零个或多个任意字符,空行也包含在内。

(8)指定要过滤字符出现的次数:

1
2
3
4
5
6
7
8
[root@localhost ~]# grep 'o\{2\}' /etc/passwd
root:x:0:0:usr:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
hadoop:x:1000:1000:Hadoop:/home/hadoop:/bin/bash
setroubleshoot:x:990:984::/var/lib/setroubleshoot:/sbin/nologin

这里用到了{ },其内部为数字,表示前面的字符要重复的次数。上例中表示包含有两个o 即 ‘oo’ 的行。注意,{ }左右都需要加上脱意字符 ‘\’,
另外,使用{ }我们还可以表示一个范围的,具体格式是 ‘{n1,n2}’
其中n1<n2,表示重复n1到n2次前面的字符,n2还可以为空,则表示大于等于n1次。

egrep:

是grep的扩展版本,可以用egrep完成grep不能完成的工作,当然了grep能完成的egrep完全可以完成。

(1)筛选一个或一个以上前面的字符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@localhost ~]# cat test.txt 
t: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·
#筛选一个或多个前面是o的字符
[root@localhost ~]# egrep 'o+' test.txt
t: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
#筛选一个或多个前面是oo的字符
[root@localhost ~]# egrep 'oo+' test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
#筛选一个或多个前面是ooo的字符
[root@localhost ~]# egrep 'ooo+' test.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep 'oooo+' test.txt
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]#

(2)筛选零个或一个前面的字符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@localhost ~]# egrep 'o?' test.txt 
t: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·
[root@localhost ~]# egrep 'oo?' test.txt
t: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
[root@localhost ~]# egrep 'ooo?' test.txt
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
[root@localhost ~]# egrep 'oooo?' test.txt
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash

(3)筛选字符串1或者字符串2:

1
2
3
4
5
[root@localhost ~]# egrep 'aaa|111|ooo' test.txt 
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa·

(4)egrep中()的应用:

用( )表示一个整体,例如(oo)+就表示1个 ‘oo’ 或者多个 ‘oo’

1
2
3
[root@localhost ~]# egrep '(111)|(aa)' test.txt 
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa·

sed工具的使用:

sed全称是:Stream EDitor。(流编辑器)

SED是一项Linux指令,功能同awk类似,差别在于,sed简单,对列处理的功能要差一些,awk的功能复杂,对列处理的功能比较强大。

grep工具的功能其实还不够强大,grep实现的只是查找功能,而它却不能实现把查找的内容替换掉。以前用vim的时候,可以查找也可以替换,但是只局限于在文本内部来操作,而不能输出到屏幕上。sed工具以及下面要讲的awk工具就能实现把替换的文本输出到屏幕上的功能了,而且还有其他更丰富的功能。sed和awk都是流式编辑器,是针对文档的行来操作的。

语法:sed 参数 文件

-e command,–expression=command允许多台编辑。

-h,–help打印帮助,并显示bug列表的地址。

-n,–quiet,–silent取消默认输出。

-f,–filer=script-file引导sed脚本文件名。

-V,–version打印版本和版权信息。

动作说明

  • a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
  • c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
  • d :删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
  • i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
  • p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
  • s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

sed应用示例:

(1)打印某行:

sed -n 'n'p filename 单引号内的n是一个数字,表示第几行:

要想把所有行都打印出来可以使用 sed -n '1,$'p filename

-n:取消默认输入,只输出指定的行。

p表示打印行。

1
2
3
4
5
6
7
8
9
[root@localhost ~]# sed -n  '2'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# sed -n '1,$'p test.txt
t: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·

也可以指定一个区间:

1
2
3
4
[root@localhost ~]# sed -n  '1,3'p test.txt 
t:x:0:0:/rot:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin

(2)打印包含某个字符串的行:

1
2
[root@localhost ~]# sed -n '/root/'p test.txt 
operator:x:11:0:operator:/root:/sbin/nologin

(3)-e可以实现多个行为:

1
2
3
[root@localhost ~]# sed -e '1'p -e '/111/'p -n test.txt
t:x:0:0:/rot:/bin/bash
1111111111111111111111111111111

(4)删除某行或者多行:

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

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# sed '1'd test.txt 
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·
[root@localhost ~]# sed '1,3'd test.txt
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa·
[root@localhost ~]#

(5)替换字符或字符串:

‘s’ 就是替换的命令, ‘g’ 为本行中全局替换,如果不加 ‘g’ 只换该行中出现的第一个。除了可以使用 ‘/’ 作为分隔符外,还可以使用其他特殊字符例如 ‘#’ 或者 ‘@’ 都没有问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost ~]# cat test.txt 
t: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·
[root@localhost ~]# sed '1,2s/ot/to/g' test.txt
t:x:0:0:/rto:/bin/bash
operator:x:11:0:operator:/roto:/sbin/nologin
operator:x:11:0:operator:/rooot:/sbin/nologin
roooot:x:0:0:/rooooot:/bin/bash
1111111111111111111111111111111
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa·
#将111全部都替换成222
[root@localhost ~]# sed 's/111/222/g' test.txt
t: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
2222222222222222222222222222221
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa·

(6)调换两个字符串的位置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~]# cat test.txt
t: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·
[root@localhost ~]# sed 's/\(rot\)\(.*\)\(bash\)/\3\2\1/' test.txt
t:x:0:0:/bash:/bin/rot
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·

上例中用 () 把所想要替换的字符括起来成为一个整体,因为括号在sed中属于特殊符号,所以需要在前面加脱意字符 ‘’, 替换时则写成 ‘1’, ‘‘2’, ‘‘3’ 的形式。

1
2
3
4
5
6
7
[root@localhost ~]# sed 's/^.*$/123&/' test.txt
123t:x:0:0:/rot:/bin/bash
123operator:x:11:0:operator:/root:/sbin/nologin
123operator:x:11:0:operator:/rooot:/sbin/nologin
123roooot:x:0:0:/rooooot:/bin/bash
1231111111111111111111111111111111
123aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa·

在所有行前面加123.

(7)直接修改文件的内容:

1
2
3
4
5
6
7
8
[root@localhost ~]# sed -i 's/111/222/g' test.txt
[root@localhost ~]# cat test.txt
t: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
2222222222222222222222222222221
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa·

awk工具的使用:

AWK是一种处理文本文件的语言,是一个强大的文本分析工具。

之所以叫AWK是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的Family Name的首字符。

语法:

1
2
3
awk [选项参数] 'script' var=value file(s)

awk [选项参数] -f scriptfile var=value file(s)

awk常见应用:

(1)截取文档中的某个段:

1
2
3
[root@localhost ~]# head -n2 /etc/passwd  | awk -F ':' '{print $1}'
root
bin

解释一下,-F 选项的作用是指定分隔符,如果不加-F指定,则以空格或者tab为分隔符。 Print为打印的动作,用来打印出某个字段。\$1为第一个字段,\$2为第二个字段,依次类推,有一个特殊的那就是$0,它表示整行。

注意awk的格式,-F后紧跟单引号,然后里面为分隔符,print的动作要用 { } 括起来,否则会报错。print还可以打印自定义的内容,但是自定义的内容要用双引号括起来。

(2)匹配字符或字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# awk '/222/' test.txt
2222222222222222222222222222221
#以冒号分隔,让第一个字符段中匹配有00,
[root@localhost ~]# awk -F ':' '$1 ~/oo/' test.txt
roooot:x:0:0:/rooooot:/bin/bash

#多次匹配
[root@localhost ~]# awk -F ':' '/root/ {print $1,$3} /test/ {print $1,$3}' /etc/passwd
root 0
operator 11
test 1003
test1 1004
[root@localhost ~]#

(3)条件操作符:

awk中是可以用逻辑符号判断的,比如 ‘==’ 就是等于,也可以理解为 ‘精确匹配’ 另外也有 >, ‘>=, ‘<, ‘<=, ‘!= 等等,值得注意的是,即使\$3为数字,awk也不会把它当数字看待,它会认为是一个字符。所以不要妄图去拿$3当数字去和数字做比较。

!= 为不匹配

另外还可以使用 && 和 || 表示 “并且” 和 “或者” 的意思。

1
2
[root@localhost ~]# awk -F ':' '$3=="0"' /etc/passwd
root:x:0:0:root:/root:/bin/bash

(4)awk的内置变量:

awk常用的变量有:

NF :用分隔符分隔后一共有多少段

NR :行数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost ~]# head -n3 /etc/passwd 
root:x:0:0:usr:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print NF}'
7
7
7
[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print $NF}'
/bin/bash
/sbin/nologin
/sbin/nologin
[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print NR}'
1
2
3

可以使用行号作为判断条件:

1
2
3
4
5
6
7
8
[root@localhost ~]# awk 'NR>40' /etc/passwd
gnome-initial-setup:x:989:983::/run/gnome-initial-setup/:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
cao:x:1001:1001::/home/cao:/bin/bash
usr:x:1002:1002:用户,offic,1234567,123:/home/usr:/bin/bash
test:x:1003:1003::/home/test:/bin/bash
test1:x:1004:1003::/home/test1:/bin/bash

(5)awk中的数学运算:

1
2
3
4
5
6
7
8
[root@localhost ~]# head  -n 3 /etc/passwd | awk -F ':' '$1="root"'
root x 0 0 usr /root /bin/bash
root x 1 1 bin /bin /sbin/nologin
root x 2 2 daemon /sbin /sbin/nologin
#可以进行数学运算
[root@localhost ~]# head -n 3 /etc/passwd | awk -F ':' '$2=$3+$4'
bin 2 1 1 bin /bin /sbin/nologin
daemon 4 2 2 daemon /sbin /sbin/nologin
坚持原创技术分享,您的支持将鼓励我继续创作!