博客地址:http://www.moonxy.com

一、前言

正则表达式(英语为 Regular Expression,在代码中常简写为 regex、regexp 或 RE),是使用单个字符串来描述或匹配一系列符合某个句法规则的字符串。许多工具和程序设计语言都支持利用正则表达式进行字符串操作,在 Linux 中,常用的 grep、sed 和 awk 等命令,也都支持正则表达式。

Linux 中正则表达式和通配符的区别:正则表达式用来找文件内容、文本和字符串等,一般只有 grep、sed 和 awk 支持,这三个命令也通常被称为 Linux 文本处理三剑客;而通配符用来找文件名,普通命令都支持,通配符主要有星号(*)问号(?),星号代表零个或多个任意字符,问号只代表一个任意的字符。

此外,对于 grep 命令而言,又可分为:

grep 是很常见也很常用的命令,它的主要功能是进行字符串数据的比较,然后符合用户需求的字符串打印出来。但是注意,grep 在数据中查找一个字符串时,是以 "整行" 为单位进行数据筛选的。

egrep 命令等同于 grep -E,利用此命令可以使用扩展的正则表达式对文本进行搜索,并把符合用户需求的字符串打印出来。

fgrep 命令等同于 grep -F,它利用固定的字符串来对文本进行搜索,但不支持正则表达式的引用,所以此命令的执行速度也最快。

二、正则表达式分类

Linux 正则表达式一般分为 BRE(Basic Regular Expression) 和 ERE(Extended Regular Expression)。前者为基本正则表达式,后者为扩展正则表达式。他们都遵循 POSIX 规范,POSIX 指的是可移植操作系统接口。ERE 是 BRE 的扩展版本,具有更强的处理能力,并且增加了一些元字符(metacharactor)。Linux 的 grep 默认使用 BRE,可以通过 egrep 或者 grep -E 来开启使用 ERE。Linux 的 sed 使用 BRE 中的一个子集,主要是为了保证处理的速度和效率。BRE 与 ERE 在能力上区别仅在多项匹配的能力上,其他方面没有大的差别,主要的区别体现在元字符上。

比如:

BRE(基础正则表达式)只认识的元字符有 ^$.[]*,其他字符识别为普通字符,如 "()",要使用此功能必须加 "\" 进行转义,即 "\(\)";

ERE(扩展正则表达式)则添加了 (){}?+| 等元字符;

只有在用反斜杠 "\" 进行转义的情况下,字符 (){} 才会在BRE被当作元字符处理,而ERE中,任何元符号前面加上反斜杠反而会使其被当作普通字符来处理。

三、BRE 基本正则表达式

3.1 元字符 ^

比如 ^word ,表示搜索以 word 开头的内容,即此字符后面的任意内容必须出现在行首

[root@ryan linux]# cat -n test2
1 bob:26:shanxi:138912:linux
2
3 ryan:28:china:23124:java
4 adam:30:xinjiang:123123:python
5
6 emily:20:beijing:35345:scala
7 ada:16:shengjiang:123321:rubby

[root@ryan linux]# grep ^ad test2
adam:30:xinjiang:123123:python
ada:16:shengjiang:123321:rubby

3.2 元字符 $

比如 word$ 搜索以 word 结尾的内容,即此字符前面的任意内容必须出现在行尾

[root@ryan linux]# grep a$ test2
ryan:28:china:23124:java
emily:20:beijing:35345:scala

3.3 表达式 ^$

^$ 表示空行,不是空格

[root@ryan linux]# grep -n ^$ test2
2:
5:

第 2 行和第 5 行都是空行。

3.4 元字符 .

. 代表且只能代表任意一个字符(不匹配空行)

[root@ryan linux]# grep -n "." test2
1:bob:26:shanxi:138912:linux
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby

[root@ryan linux]# grep -n ".y" test2
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby

3.5 转义字符 \

\ 转义字符,让有特殊含义的字符脱掉马甲,现出原形,如 \.只表示小数点

[root@ryan linux]# cat -n test2
1 bob:26:shanxi:138912:linux
2
3 ryan:28:china:23124:java
4 adam:30:xinjiang:123123:python
5
6 emily:20:beijing:35345:scala
7 ada:16:shengjiang:123321:rubby
8 jim.green:18:shandong:123321:rubby
9 tom:16:hebei:123321:ru.bby

[root@ryan linux]# grep "\." test2
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby

[root@ryan linux]# grep "\.g" test2
jim.green:18:shandong:123321:rubby

3.6 元字符 *

重复之前的字符或文本0个或多个,之前的文本或字符连续0次或多次,即匹配其前面的字符任意次

[root@ryan linux]# grep "e*" test2
bob:26:shanxi:138912:linux

ryan:28:china:23124:java
adam:30:xinjiang:123123:python

emily:20:beijing:35345:scala
ada:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby

* 匹配前一个字符0个或多个,假如匹配0个的时候,实际上就等于空,什么都没有。什么都没有的情况下就默认匹配文件的全部内容,然后再匹配大于0的情况。

3.7 表达式 .*

.* 匹配任意多个字符

[root@ryan linux]# grep -n ".*" test2
1:bob:26:shanxi:138912:linux
2:
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
5:
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby

3.8 表达式 ^.*

^.* 以任意多个字符串开头

[root@ryan linux]# grep -n "^.*" test2
1:bob:26:shanxi:138912:linux
2:
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
5:
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby

[root@ryan linux]# grep -n "^.*a" test2
1:bob:26:shanxi:138912:linux
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby

3.9 括号表达式 [ ]

[abc][0-9][\.,/],匹配字符集合内的任意一个字符 a 或 b 或 c:[a-z] 匹配所有小写字母;表示一个整体,内藏无限可能;[abc] 找 a 或 b 或 c 可以写成 [a-c]

[root@ryan linux]# grep -n "[abc]" test2
1:bob:26:shanxi:138912:linux
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby

[root@ryan linux]# grep -n "[0-9]" test2
1:bob:26:shanxi:138912:linux
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby

[root@ryan linux]# grep -n "[\.,/]" test2
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby

[root@ryan linux]# cat -n test2
1 bob:26:shanxi:138912:linux
2
3 ryan:28:china:23124:java
4 adam:30:xinjiang:123123:python
5
6 emily:20:beijing:35345:scala
7 ada:16:shengjiang:123321:rubby
8 jim.green:18:shandong:123321:rubby
9 tom:16:hebei:123321:ru.bby
10 http://www.baidu.com/music\document,mp3
[root@ryan linux]# grep -n "[\.,/]" test2
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby
10:http://www.baidu.com/music\document,mp3

3.10 表达式 [^abc]

匹配不包含 ^ 后的任意字符 a 或 b 或 c,是对 [abc] 的取反,且与 ^ 含义不同

[root@ryan linux]# grep -n "[^abc]" test2
1:bob:26:shanxi:138912:linux
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby
10:http://www.baidu.com/music\document,mp3

[root@ryan linux]# grep -n "^[abc]" test2
1:bob:26:shanxi:138912:linux
4:adam:30:xinjiang:123123:python
7:ada:16:shengjiang:123321:rubby

[^abc] 匹配不包含 a、b 或 c 的字符串,而 ^[abc] 匹配以 a、b 或 c 开头的行。

注意:我发现 "^" 这个字符在中括号 "[ ]" 中被使用的话就表示字符类的否定,如果不是的话就是表示限定开头。我这里说的是直接在"[ ]" 中使用,不包括嵌套使用。其实也就是说 "[ ]" 代表的是一个字符集,"^" 只有在字符集中才是反向字符集的意思。

3.11 a\{m,n\}

重复前面 a 字符 m 到 n 次,即匹配其前面的字符至少 m 次,至多 n 次(如果用 egrep 或 sed -r 可去掉转义字符反斜杠 "\")

[root@ryan linux]# grep -n "w{1,3}" test2

直接运行之后,grep 匹配不到字符,说明 grep 默认不支持大括号匹配,可以添加参数 -E,表明使用扩展正则表达式,如下:

[root@ryan linux]# grep -nE "w{1,3}" test2
10:http://www.baidu.com/music\document,mp3

或者使用转义字符,如下:
[root@ryan linux]# grep -n "w\{1,3\}" test2
10:http://www.baidu.com/music\document,mp3

a\{m,\} 重复前面 a 字符至少 m 次,如果用 egrep 或 sed -r 可去掉转义字符反斜杠 "\";

a\{m\} 重复前面 a 字符 m 次,如果用 egrep 或 sed -r 可去掉转义字符反斜杠 "\";

注意:

1) ^ 字符是否在 [ ] 中,作用是不同的;

2) * 字符在正则表达式中的作用与其充当通配符时的作用不同;

3) ! 字符在正则表达式中并不是特殊字符;

四、ERE 扩展正则表达式

grep 默认不支持扩展正则元符号,因此扩展正则表达式的符号对于 grep 来说就等同于普通字符含义,因此,想让 grep 直接处理正则符号可以通过转义字符 \{\} 来处理,或使用 grep -E 强制让 grep 直接认识扩展正则元符号,不需要再进行转义。 egrep 等效于 grep -E,直接支持扩展正则元符号。sed 通过使用 sed -r 支持扩展正则元符号。

4.1 元字符 +

重复前一个字符一次或一次以上,前一个字符连续一个或多个,把连续的文本或字符取出

[root@ryan linux]# grep -nE "e+" test2
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby
10:http://www.baidu.com/music\document,mp3

4.2 元字符 ?

重复前面一个字符0次或1次(.是有且只有1个)

[root@ryan linux]# grep -nE "e?" test2
1:bob:26:shanxi:138912:linux
2:
3:ryan:28:china:23124:java
4:adam:30:xinjiang:123123:python
5:
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby
10:http://www.baidu.com/music\document,mp3

[root@ryan linux]# grep -nE "e." test2
6:emily:20:beijing:35345:scala
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby
10:http://www.baidu.com/music\document,mp3

4.3 管道符 |

| 表示或者同时过滤多个字符

[root@ryan linux]# grep -n "138|912|123" test2

[root@ryan linux]# grep -n "138\|912\|123" test2
1:bob:26:shanxi:138912:linux
4:adam:30:xinjiang:123123:python
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby

[root@ryan linux]# grep -nE "138|912|123" test2
1:bob:26:shanxi:138912:linux
4:adam:30:xinjiang:123123:python
7:ada:16:shengjiang:123321:rubby
8:jim.green:18:shandong:123321:rubby
9:tom:16:hebei:123321:ru.bby

4.4 元字符 ( )

() 分组过滤被括起来的东西表示一个整体 (一个字符),后向引用

[root@ryan linux]# grep -nE "(xin|sheng)jiang" test2
4:adam:30:xinjiang:123123:python
7:ada:16:shengjiang:123321:rubby

等效于 AB + AC = A(B +C)

五、补充

5.1 预定义的正则表达式

只有 ERE 才支持:

5.2 其他元字符

BRE 已经支持:

正则表达式只有多加练习,才能很好的融会贯通,配合 grep,egrep,sed -r,awk 等工具。

六、sed 工具的使用

虽然 grep 已经有很强大的功能了,但是只能实现查找功能,而不能实现替换等操作。sed 是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换、删除、新增、选取等特定工作,下面先了解一下 sed 的用法。

格式:sed [-nefri] 'command' 文本

常用选项:

-n∶使用安静 (silent )模式。在一般 sed 的用法中,所有来自 STDIN 的资料一般都会被列出到屏幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来;
-e∶直接在指令列模式上进行 sed 的动作编辑;
-f∶直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作;
-r∶使 sed 的动作支持 ERE 的语法,预设是 BRE 语法;
-i∶直接修改读取的档案内容,而不是由屏幕输出;

常用命令:

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

6.1 打印某行

打印第2行,如下:

[root@ryan linux]# cat -n test3.txt
1 bob:26:shanxi:138912:linux
2 ryan:28:china:23124:java
3 adam:30:xinjiang:123123:python
4 emily:20:beijing:35345:scala
5 ada:16:shengjiang:123321:rubby
6 jim.green:18:shandong:123321:rubby
7 tom:16:hebei:123321:ru.bby
8 http://www.baidu.com/music\document,mp3
9 The negotiation went well and they finally reached an agreement.
[root@ryan linux]# sed -n '2'p test3.txt
ryan:28:china:23124:java

打印所有行,如下:

[root@ryan linux]# sed -n '1,$'p test3.txt
bob:26:shanxi:138912:linux
ryan:28:china:23124:java
adam:30:xinjiang:123123:python
emily:20:beijing:35345:scala
ada:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.

打印指定区间的行,如下:

[root@ryan linux]# sed -n '2,5'p test3.txt
ryan:28:china:23124:java
adam:30:xinjiang:123123:python
emily:20:beijing:35345:scala
ada:16:shengjiang:123321:rubby

6.2 打印包含某个字符串的行

[root@ryan linux]# sed -n '/adam/'p test3.txt
adam:30:xinjiang:123123:python

也可使用 ^、$、.、*等元字符,如下:

[root@ryan linux]# sed -n '/ad./'p test3.txt
adam:30:xinjiang:123123:python
ada:16:shengjiang:123321:rubby

6.3 删除某行或多行

单个数字表示删除某行,删除1到3行,如下:

[root@ryan linux]# sed '1,3'd test3.txt
emily:20:beijing:35345:scala
ada:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.

删除匹配到的行,如下:

[root@ryan linux]# sed '/ad./'d test3.txt
bob:26:shanxi:138912:linux
ryan:28:china:23124:java
emily:20:beijing:35345:scala
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.

6.4 替换字符或字符串

格式:sed 's/要替换的字符串/新的字符串/g'   (要替换的字符串可以用正则表达式)

[root@ryan linux]# sed '1,3s/ada/robot/g' test3.txt
bob:26:shanxi:138912:linux
ryan:28:china:23124:java
robotm:30:xinjiang:123123:python
emily:20:beijing:35345:scala
ada:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.

[root@ryan linux]# sed '/ad./s/ada/robot/g' test3.txt
bob:26:shanxi:138912:linux
ryan:28:china:23124:java
robotm:30:xinjiang:123123:python
emily:20:beijing:35345:scala
robot:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.

参数 g 表示本行全局替换,如果不加 g 则只替换本行出现的第一个。除了可以使用 / 作为分隔符外,我们还可以使用其他特殊字符,例如 # 和 @

[root@ryan linux]# sed '/ad./s#ada#robot#g' test3.txt
bob:26:shanxi:138912:linux
ryan:28:china:23124:java
robotm:30:xinjiang:123123:python
emily:20:beijing:35345:scala
robot:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.

也可以替换文档中所有的数字或者字母,如下:

[root@ryan linux]# sed 's/[0-9]//g' test3.txt
bob::shanxi::linux
ryan::china::java
adam::xinjiang::python
emily::beijing::scala
ada::shengjiang::rubby
jim.green::shandong::rubby
tom::hebei::ru.bby
http://www.baidu.com/music\document,mp
The negotiation went well and they finally reached an agreement.

[root@ryan linux]# sed 's/[a-zA-Z]//g' test3.txt
:26::138912:
:28::23124:
:30::123123:
:20::35345:
:16::123321:
.:18::123321:
:16::123321:.
://../\,3
.

也可使用 sed 's/[0-9a-zA-Z]//g' test3.txt

[root@ryan linux]# cat test3.log
aabbccddeeffgghh
[root@ryan linux]# sed 's/^\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4/' test3.log
aa:bb:cc:dd

说明:

其中^表示从一行的开头匹配
第一个\(..\)表示匹配任意2个字符,并且后面的 \1,就是这次匹配的结果;
对于字符串 aabbccddeeffgghh 而言,就是 aa 这2个字符;
同理,第二\(..\)匹配bb,对应 \2;
第三\(..\)匹配 cc,对应 \3;
第四\(..\)匹配 dd,对应 \4;
剩下的 eeffgghh 匹配 .*$,其中 .* 表示匹配任意个字符,$ 匹配到末尾,这些字符串被抛弃;
aabbccddeeffgghh 得到的结果就是 aa:bb:cc:dd。

这里\1 和\2 的意思其实就是引用第 一,二 个 () 里的内容。() 括号的意思就是,当你执行替换的时候不是整行替换,而且替换 () 里的内容。

[root@ryan linux]# cat test3
total 92
-rw-r--r--. 1 root root 40 Mar 31 19:29 1
-rw-r--r--. 1 root root 13368 Mar 20 20:46 file.log
-rw-r--r--. 1 root root 13368 Mar 18 17:48 install.log
drwxr-xr-x. 2 root root 4096 Mar 31 20:03 split_dir
drwxr-xr-x+ 2 root root 4096 Dec 3 13:35 test
drwxr-xr-x. 2 root root 4096 Nov 26 03:46 test1
-rw-r--r--. 1 root root 158 Mar 20 21:11 test1.tar.bz2
-rw-r--r--. 1 root root 161 Mar 18 22:02 test1.tar.gz
-rw-r--r--. 1 root root 208 Mar 21 22:24 test1.tar.xz
-rw-r--r--. 1 root root 7 Mar 31 13:38 test1.txt
-rw-r--r--. 1 root root 162 Mar 20 21:21 test1.zip
-rw-r--r-- 1 root root 312 Apr 5 22:58 test2
-rw-r--r-- 1 root root 0 Apr 7 11:32 test3
-rw-r--r--. 1 root root 310 Apr 7 11:21 test3.txt
drwxr-xr-x. 3 root root 4096 Mar 20 21:24 test4
-rw-r--r--. 1 root root 678 Mar 20 21:31 test4.zip
-rwxr-xr-x. 1 root root 43 Apr 3 22:08 test.sh

[root@ryan linux]# sed -r 's/\s{1,}/#/g' test3
total#92
-rw-r--r--.#1#root#root#40#Mar#31#19:29#1
-rw-r--r--.#1#root#root#13368#Mar#20#20:46#file.log
-rw-r--r--.#1#root#root#13368#Mar#18#17:48#install.log
drwxr-xr-x.#2#root#root#4096#Mar#31#20:03#split_dir
drwxr-xr-x+#2#root#root#4096#Dec#3#13:35#test
drwxr-xr-x.#2#root#root#4096#Nov#26#03:46#test1
-rw-r--r--.#1#root#root#158#Mar#20#21:11#test1.tar.bz2
-rw-r--r--.#1#root#root#161#Mar#18#22:02#test1.tar.gz
-rw-r--r--.#1#root#root#208#Mar#21#22:24#test1.tar.xz
-rw-r--r--.#1#root#root#7#Mar#31#13:38#test1.txt
-rw-r--r--.#1#root#root#162#Mar#20#21:21#test1.zip
-rw-r--r--#1#root#root#312#Apr#5#22:58#test2
-rw-r--r--#1#root#root#0#Apr#7#11:32#test3
-rw-r--r--.#1#root#root#310#Apr#7#11:21#test3.txt
drwxr-xr-x.#3#root#root#4096#Mar#20#21:24#test4
-rw-r--r--.#1#root#root#678#Mar#20#21:31#test4.zip
-rwxr-xr-x.#1#root#root#43#Apr#3#22:08#test.sh

6.5 直接修改文件的内容

[root@ryan linux]# cat test3.txt
bob:26:shanxi:138912:linux
ryan:28:china:23124:java
adam:30:xinjiang:123123:python
emily:20:beijing:35345:scala
ada:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.
[root@ryan linux]# sed -i 's/ada/robot/g' test3.txt
[root@ryan linux]# cat test3.txt
bob:26:shanxi:138912:linux
ryan:28:china:23124:java
robotm:30:xinjiang:123123:python
emily:20:beijing:35345:scala
robot:16:shengjiang:123321:rubby
jim.green:18:shandong:123321:rubby
tom:16:hebei:123321:ru.bby
http://www.baidu.com/music\document,mp3
The negotiation went well and they finally reached an agreement.

七、awk 工具的使用

awk 是一个强大的文本分析工具,相对于 grep 的查找,sed 的编辑,awk 在其对数据分析并生成报告时,显得尤为强大。简单来说 awk 就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

注意:awk 以空格为分割域时,是以单个或多个连续的空格为分隔符的;cut 则是以单个空格作为分隔符。

7.1 截取文档中的某个段

[root@ryan linux]# cat test4.log
-rw-r--r--.#1#root#root#40#Mar#31#19:29#1
-rw-r--r--.#1#root#root#13368#Mar#20#20:46#file.log
-rw-r--r--.#1#root#root#13368#Mar#18#17:48#install.log
drwxr-xr-x.#2#root#root#4096#Mar#31#20:03#split_dir
drwxr-xr-x+#2#root#root#4096#Dec#3#13:35#test

[root@ryan linux]# awk -F '#' '{print $1}' test4.log
-rw-r--r--.
-rw-r--r--.
-rw-r--r--.
drwxr-xr-x.
drwxr-xr-x+

-F 选项的作用是指定分隔符,如果不加 -F 选项,则以空格或者 tab 为分隔符。print 表示打印的动作,用来打印某个段,$1表示第1个字段,$2为第2个字段,以此类推。$0比较特殊,它表示整行。print 动作要用 {} 括起来,否则会报错。

print 还可以打印自定义的内容,但是自定义的内容要用双引号括起来,如下:

[root@ryan linux]# awk -F '#' '{print $1":"$3":"$4":"$9}' test4.log
-rw-r--r--.:root:root:1
-rw-r--r--.:root:root:file.log
-rw-r--r--.:root:root:install.log
drwxr-xr-x.:root:root:split_dir
drwxr-xr-x+:root:root:test

7.2 匹配字符或者字符串

[root@ryan linux]# awk '/robot/' test3.txt
robotm:30:xinjiang:123123:python
robot:16:shengjiang:123321:rubby

7.3 条件操作符

awk 中可以用逻辑符号进行判断,比如 == 表示等于,另外还有 >、>=、<、<=、!= 等,在和数字比较时,不能把数字用括号括起来,否则,awk 会认为是字符,而不是数字。

[root@ryan linux]# awk -F ':' '$3>=100' /etc/passwd
saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
rtkit:x:498:496:RealtimeKit:/proc:/sbin/nologin
pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
adam:x:500:500::/home/adam:/bin/bash
bob:x:501:501:bob-xu,hsbc,1008611,1008612:/home/bob:/bin/bash

也可以两个字段之间进行逻辑比较,如下:

[root@ryan linux]# awk -F ':' '$3!=$4' /etc/passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
……

还可以使用 && 和 ||,分别表示 "并且" 和 "或者",如下:

[root@ryan linux]# awk -F ':' '$3>500 && $3<700' /etc/passwd
bob:x:501:501:bob-xu,hsbc,1008611,1008612:/home/bob:/bin/bash

7.4 awk 的内置变量

awk 常用的变量有 NF 和 NR,NF 表示用分隔符分隔后一共有多少段,NR 表示行号。

[root@ryan linux]# awk -F ':' '{print NF}' /etc/passwd
7
7
7
……

[root@ryan linux]# awk -F ':' '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
……

[root@ryan linux]# awk -F ':' '{print NR}' /etc/passwd
1
2
3
……

[root@ryan linux]# awk 'NR>=1 && NR <=3' /etc/passwd

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

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

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

[root@ryan linux]# awk 'NR>=1 && NR <=3' /etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin

7.5 awk 常见的使用场景

使用 awk 命令获取文本的某一行,某一列,如下:

打印文件的第一列(域) : awk '{print $1}' filename

打印完第一列,然后打印第二列 : awk '{print $1 $2}' filename

打印文本文件的总行数 : awk 'END{print NR}' filename

打印文本第一行 :awk 'NR==1{print}' filename

打印文本第二行的第一列 :sed -n '2'p filename|awk -F ':' '{print $1}' 或 awk -F ':' 'NR==2{print $1}' filename

打印文本最后一行:awk 'END {print}' filename

打印文本最后一行的第二列:awk -F ':' 'END {print $2}' filename

这里的 END 是 awk 特有的语法,表示所有的行都已经执行。

在 Shell 里面,如果想将命令的运行结果赋值给某个变量,可采用如下两种方式,格式为

1) arg=`(命令)`

2) arg=$(命令)

因此,如果想要把某一文件的总行数赋值给变量 nlines,可以表达为:

1) nlines=`(awk 'END{print NR}' filename)`

或者

2) nlines=$(awk 'END{print NR}' filename)

八、正则表达式的最短与最长匹配

贪婪与懒惰规则

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。考虑这个表达式:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索 aabab 的话,它会匹配整个字符串 aabab。这被称为贪婪匹配。

但是有时后,我们也需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号 ?,问号表示匹配前面的内容0次或1次。这样 .*? 就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复,即最多匹配一次。现在看看懒惰版的例子:

a.*?b 匹配最短的,以 a 开始,以 b 结束的字符串。如果把它应用于 aabab 的话,它会分别匹配 aab(第一到第三个字符)和 ab(第四到第五个字符)。

为什么第一个匹配是 aab(第一到第三个字符)而不是 ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The match that begins earliest wins

懒惰限定符

正则表达式也可以返回子匹配结果

$1,$2……是表示的小括号里的内容,其中 $1是第1个小括号里的内容,$2是第2个小括号里的内容,依次类推。

比如 /gai([\w]+?)over([\d]+)/

匹配 gainover123

$1为第1个括号里的 n;

$2为第2个括号里的 123。

转载于:https://www.cnblogs.com/cnjavahome/p/8719534.html

Linux 笔记 - 第十一章 正则表达式相关推荐

  1. Linux(b站视频兄弟连)自学笔记第十一章——shell编程

    Linux(b站视频兄弟连)自学笔记第十一章--shell基础 正则表达式 字符截取命令 cut命令 printf命令 awk命令 sed命令 字符处理命令 判断条件 流程控制 if语句 case语句 ...

  2. 《Go语言圣经》学习笔记 第十一章 测试

    <Go语言圣经>学习笔记 第十一章 测试 目录 go test 测试函数 测试覆盖率 基准测试 剖析 示例函数 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语 ...

  3. 【JAVA SE】第十一章 正则表达式、包装类和BigDecimal

    第十一章 正则表达式.包装类和BigDecimal 文章目录 第十一章 正则表达式.包装类和BigDecimal 一.正则表达式 二.包装类 1.概述 2.装箱与拆箱: 3.基本数据和包装类之间的转换 ...

  4. 《金融学》笔记 第十一章 货币政策

    <金融学>笔记 第十一章 货币政策 前言 在<<金融学>笔记>中开了一个头,现在完善具体细节. 金融范畴篇 第一章 货币的本质 第二章 货币制度 第三章 信用.利息 ...

  5. [go学习笔记.第十一章.项目案例] 2.客户信息管理系统

    一.基本介绍 1.需求说明 项目需求分析 1.模拟实现基于文本界面的 < 客户信息管理软件 > 2.该软件实现对客户对象的插入.修改和删除(用切片实现),并能够打印客户明细表 2.界面设计 ...

  6. [go学习笔记.第十一章.项目案例] 1.家庭收支记账软件项目

    一.基本介绍 1.项目开发流程说明 2.项目需求说明 目标: 模拟实现一个基于文本界面的<<家庭记账软件>> 掌握初步的编程技巧和调试技巧 主要涉及以下知识点 : (1).局部 ...

  7. 《统计学习方法》学习笔记 第二十一章 PageRank算法

    目录 1 PageRank的定义 1.1 基本想法 1.2 有向图和随机游走模型 1 有向图(directed graph) 2 随机游走模型 3 PageRank的基本定义 4 PageRank的一 ...

  8. [swift 进阶]读书笔记-第十一章:互用性 C11P1 实践:封装 CommonMark

    第十一章:互用性 Interoperability 前言: swift 的最大优点就是与C 或者 OC 混编的时候稳的一匹 本章主要讲了swift和C之间的一些知识点. 11.1 实践:封装 Comm ...

  9. Computer Vision: A Modern Approach - 计算机视觉书籍阅读笔记 -第十一章 - 跟踪

    Book name : Computer Vision: A Modern Approach Book URL: https://www.academia.edu/38213969/Computer_ ...

最新文章

  1. linux镜像文件不要大于4g,Systemback制作大于4G的Ubuntu系统镜像
  2. 大型JavaScript应用程序架构模式
  3. Python爬虫的经典多线程方式,生产者与消费者模型
  4. 【openMV】OpenMV4基础知识
  5. 蓝桥杯 算法训练 结点选择
  6. Dev XtraTreeList 学习笔记
  7. kube-proxy修改成ipvs模式
  8. 开发框架:AdminLTE
  9. 正则表达式功能以及应用
  10. 各种版本的Linux 镜像下载网址
  11. 学计算机的学后感,计算机学习心得体会(通用10篇)
  12. ArcGIS安装1606错误解决办法-清理注册表
  13. C语言程序设计谭浩强第五版课后答案
  14. 亚信安全助手、杀毒软件卸载
  15. 分段点处导数怎么求,导数和导函数的极限有关系吗?
  16. IT4IT的前世今生
  17. 科学表明:晚睡的人更聪明、更有创造力
  18. 【论文阅读记录】孪生网络(Siamese network)
  19. HTML重点知识小结①
  20. ciscn_2019_qual_virtual

热门文章

  1. 笔记本电脑wifi图标变成了小地球的解决办法(留日后查看)
  2. 程序员最值得听的歌曲TOP10
  3. 强大的项目管理软件:OmniPlan Pro 4 mac中文版
  4. 【ZYNQ】裸机 PS + PL 双网口实现之 lwip 库文件修改
  5. drawLine(self, Union[QPointF, QPoint], Union[QPointF, QPoint]): argument 1 has unexpected type ‘floa
  6. 微信JSAPI支付实现
  7. RPG的地牢猎手(优先队列广搜)
  8. 第六届蓝桥杯大赛个人赛决赛(C/C++大学B组)
  9. 听《武志红的心理课之潜意识就是命运》有感 命运,这个东西信者有,不信者无。我很赞同武老师的观点,一个热的外在命运和我们的内在想象,是镜像关系。这不禁让我想起了小时候的一个故事:一群青蛙比赛爬山,很多人
  10. InteractiveDataDisplay.WPF 固定坐标轴