awk、grep、sed是linux操作文本的三大利器,合称文本三剑客,也是必须掌握的linux命令之一。三者的功能都是处理文本,但侧重点各不相同,其中属awk功能最强大,但也最复杂。grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。
1、grep
1.1 什么是grep和egrep
Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来(匹配到的标红)。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。
grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到标准输出,不影响原文件内容。
grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可进行一些自动化的文本处理工作。
egrep = grep -E:扩展的正则表达式 (除了\< , \> , \b 使用其他正则都可以去掉\)
1.2 使用grep
1.2.1 命令格式
1
grep [option] pattern file
1.2.2 命令功能
用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。
1.2.3 命令参数
常用参数已加粗
-A<显示行数>:除了显示符合范本样式的那一列之外,并显示该行之后的内容。
-B<显示行数>:除了显示符合样式的那一行之外,并显示该行之前的内容。
-C<显示行数>:除了显示符合样式的那一行之外,并显示该行之前后的内容。
-c:统计匹配的行数
-e :实现多个选项间的逻辑or 关系
-E:扩展的正则表达式
-f FILE:从FILE获取PATTERN匹配
-F :相当于fgrep
-i --ignore-case #忽略字符大小写的差别。
-n:显示匹配的行号
-o:仅显示匹配到的字符串
-q: 静默模式,不输出任何信息
-s:不显示错误信息。
-v:显示不被pattern 匹配到的行,相当于[^] 反向匹配
-w :匹配 整个单词
1.3 grep实战演示
2、正则表达式
2.1 认识正则
(1)介绍
正则表达式应用广泛,在绝大多数的编程语言都可以完美应用,在Linux中,也有着极大的用处。
使用正则表达式,可以有效的筛选出需要的文本,然后结合相应的支持的工具或语言,完成任务需求。
在本篇博客中,我们使用grep/egrep来完成对正则表达式的调用
(2)正则表达式类型
正则表达式可以使用正则表达式引擎实现,正则表达式引擎是解释正则表达式模式并使用这些模式匹配文本的基础软件。
在Linux中,常用的正则表达式有:
POSIX 基本正则表达式(BRE)引擎
POSIX 扩展正则表达式(BRE)引擎
2.2 基本正则表达式
2.2.1 匹配字符
(1)格式
. 匹配任意单个字符,不能匹配空行
[] 匹配指定范围内的任意单个字符
[^] 取反
[:alnum:] 或 [0-9a-zA-Z]
[:alpha:] 或 [a-zA-Z]
[:upper:] 或 [A-Z]
[:lower:] 或 [a-z]
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字 或[0-9]
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
(2)演示
2.2.2 配置次数
(1)格式
* 匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* 任意长度的任意字符,不包括0次
\? 匹配其前面的字符0 或 1次
\+ 匹配其前面的字符至少1次
\{n\} 匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m 次,至多n次
\{,n\} 匹配前面的字符至多n次
\{n,\} 匹配前面的字符至少n次
(2)演示
2.2.3 位置锚定:定位出现的位置
(1)格式
^ 行首锚定,用于模式的最左侧
$ 行尾锚定,用于模式的最右侧
^PATTERN$,用于模式匹配整行
^$ 空行
^[[:space:]].*$ 空白行
\< 或 \b 词首锚定,用于单词模式的左侧
\> 或 \b 词尾锚定;用于单词模式的右侧
\
(2)演示
2.2.4 分组和后向引用
(1)格式
① 分组:\(\) 将一个或多个字符捆绑在一起,当作一个整体进行处理
分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, ...
② 后向引用
引用前面的分组括号中的模式所匹配字符,而非模式本身
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
\2 表示从左侧起第2个左括号以及与之匹配右括号之间的模式所匹配到的字符,以此类推
\& 表示前面的分组中所有字符
③ 流程分析如下:
(2)演示
2.3 扩展正则表达式
(1)字符匹配:
. 任意单个字符
[] 指定范围的字符
[^] 不在指定范围的字符
次数匹配:
* :匹配前面字符任意次
? : 0 或1次
+ :1 次或多次
{m} :匹配m次 次
{m,n} :至少m ,至多n次
(2)位置锚定:
^ : 行首
$ : 行尾
\<, \b : 语首
\>, \b : 语尾
分组:()
后向引用:\1, \2, ...
(3)总结
除了\<, \b : 语首、\>, \b : 语尾;使用其他正则都可以去掉\;上面有演示案例,不在进行演示
3、sed
3.1 认识sed
sed 是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace ),接着用sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。如果没有使诸如‘D’ 的特殊命令,那会在两个循环之间清空模式空间,但不会清空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出或-i。
功能:主要用来自动编辑一个或多个文件, 简化对文件的反复操作
3.2 使用sed
3.2.1 命令格式
1
sed [options] '[地址定界] command' file(s)
3.2.2 常用选项options
-n:不输出模式空间内容到屏幕,即不自动打印,只打印匹配到的行
-e:多点编辑,对每行处理时,可以有多个Script
-f:把Script写到文件当中,在执行sed时-f 指定文件路径,如果是多个Script,换行写
-r:支持扩展的正则表达式
-i:直接将处理的结果写入文件
-i.bak:在将处理的结果写入文件之前备份一份
3.2.3 地址定界
不给地址:对全文进行处理
单地址:
#: 指定的行
/pattern/:被此处模式所能够匹配到的每一行
地址范围:
#,#
#,+#
/pat1/,/pat2/
#,/pat1/
~:步进
sed -n '1~2p' 只打印奇数行 (1~2 从第1行,一次加2行)
sed -n '2~2p' 只打印偶数行
3.2.4 编辑命令command
d:删除模式空间匹配的行,并立即启用下一轮循环
p:打印当前模式空间内容,追加到默认输出之后
a:在指定行后面追加文本,支持使用\n实现多行追加
i:在行前面插入文本,支持使用\n实现多行追加
c:替换行为单行或多行文本,支持使用\n实现多行追加
w:保存模式匹配的行至指定文件
r:读取指定文件的文本至模式空间中匹配到的行后
=:为模式空间中的行打印行号
!:模式空间中匹配行取反处理
s///:查找替换,支持使用其它分隔符,如:s@@@,s###;
加g表示行内全局替换;
在替换时,可以加一下命令,实现大小写转换
\l:把下个字符转换成小写。
\L:把replacement字母转换成小写,直到\U或\E出现。
\u:把下个字符转换成大写。
\U:把replacement字母转换成大写,直到\L或\E出现。
\E:停止以\L或\U开始的大小写转换
3.3 sed用法演示
3.3.1 常用选项options演示
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
26
27
28
29
30
[root@along ~]# cat demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed "/aaa/p" demo #匹配到的行会打印一遍,不匹配的行也会打印
aaa
aaa
bbbb
AABBCCDD
[root@along ~]# sed -n "/aaa/p" demo #-n不显示没匹配的行
aaa
[root@along ~]# sed -e "s/a/A/" -e "s/b/B/" demo #-e多点编辑
Aaa
Bbbb
AABBCCDD
[root@along ~]# cat sedscript.txt
s/A/a/g
[root@along ~]# sed -f sedscript.txt demo #-f使用文件处理
aaa
bbbb
aaBBCCDD
[root@along ~]# sed -i.bak "s/a/A/g" demo #-i直接对文件进行处理
[root@along ~]# cat demo
AAA
bbbb
AABBCCDD
[root@along ~]# cat demo.bak
aaa
bbbb
AABBCCDD
3.3.2 地址界定演示
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
26
27
28
[root@along ~]# cat demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed -n "p" demo #不指定行,打印全文
aaa
bbbb
AABBCCDD
[root@along ~]# sed "2s/b/B/g" demo #替换第2行的b->B
aaa
BBBB
AABBCCDD
[root@along ~]# sed -n "/aaa/p" demo
aaa
[root@along ~]# sed -n "1,2p" demo #打印1-2行
aaa
bbbb
[root@along ~]# sed -n "/aaa/,/DD/p" demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed -n "2,/DD/p" demo
bbbb
AABBCCDD
[root@along ~]# sed "1~2s/[aA]/E/g" demo #将奇数行的a或A替换为E
EEE
bbbb
EEBBCCDD
3.3.3 编辑命令command演示
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
[root@along ~]# cat demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed "2d" demo #删除第2行
aaa
AABBCCDD
[root@along ~]# sed -n "2p" demo #打印第2行
bbbb
[root@along ~]# sed "2a123" demo #在第2行后加123
aaa
bbbb
123
AABBCCDD
[root@along ~]# sed "1i123" demo #在第1行前加123
123
aaa
bbbb
AABBCCDD
[root@along ~]# sed "3c123\n456" demo #替换第3行内容
aaa
bbbb
123
456
[root@along ~]# sed -n "3w/root/demo3" demo #保存第3行的内容到demo3文件中
[root@along ~]# cat demo3
AABBCCDD
[root@along ~]# sed "1r/root/demo3" demo #读取demo3的内容到第1行后
aaa
AABBCCDD
bbbb
AABBCCDD
[root@along ~]# sed -n "=" demo #=打印行号
1
2
3
[root@along ~]# sed -n '2!p' demo #打印除了第2行的内容
aaa
AABBCCDD
[root@along ~]# sed 's@[a-z]@\u&@g' demo #将全文的小写字母替换为大写字母
AAA
BBBB
AABBCCDD
3.4 sed高级编辑命令
(1)格式
h:把模式空间中的内容覆盖至保持空间中
H:把模式空间中的内容追加至保持空间中
g:从保持空间取出数据覆盖至模式空间
G:从保持空间取出内容追加至模式空间
x:把模式空间中的内容与保持空间中的内容进行互换
n:读取匹配到的行的下一行覆盖 至模式空间
N:读取匹配到的行的下一行追加 至模式空间
d:删除模式空间中的行
D:删除 当前模式空间开端至\n 的内容(不再传 至标准输出),放弃之后的命令,但是对剩余模式空间重新执行sed
(2)一个案例+示意图演示
① 案例:倒序输出文本内容
1
2
3
4
5
6
7
8
[root@along ~]# cat num.txt
One
Two
Three
[root@along ~]# sed '1!G;h;$!d' num.txt
Three
Two
One
② 示意图如下:
③ 总结模式空间与保持空间关系:
保持空间是模式空间一个临时存放数据的缓冲区,协助模式空间进行数据处理
(3)演示
① 显示偶数行
1
2
3
4
5
[root@along ~]# seq 9 |sed -n 'n;p'
2
4
6
8
② 倒序显示
1
2
3
4
5
6
7
8
9
10
[root@along ~]# seq 9 |sed '1!G;h;$!d'
9
8
7
6
5
4
3
2
1
③ 显示奇数行
1
2
3
4
5
6
[root@along ~]# seq 9 |sed 'H;n;d'
1
3
5
7
9
④ 显示最后一行
1
2
[root@along ~]# seq 9| sed 'N;D'
9
⑤ 每行之间加空行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@along ~]# seq 9 |sed 'G'
1
2
3
4
5
6
7
8
9
---
⑥ 把每行内容替换成空行
1
2
3
4
5
6
7
8
9
10
11
[root@along ~]# seq 9 |sed "g"
---
⑦ 确保每一行下面都有一个空行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@along ~]# seq 9 |sed '/^$/d;G'
1
2
3
4
5
6
7
8
9
4、awk
4.1 认识awk
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
awk其实不仅仅是工具软件,还是一种编程语言。不过,本文只介绍它的命令行用法,对于大多数场合,应该足够用了。
4.2 使用awk
4.2.1 语法
1
2
3
awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ...
4.2.2 常用命令选项
-F fs:fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
-v var=value:赋值一个用户定义变量,将外部变量传递给awk
-f scripfile:从脚本文件中读取awk命令
4.3 awk变量
变量:内置和自定义变量,每个变量前加 -v 命令选项
4.3.1 内置变量
(1)格式
FS :输入字段分隔符,默认为空白字符
OFS :输出字段分隔符,默认为空白字符
RS :输入记录分隔符,指定输入时的换行符,原换行符仍有效
ORS :输出记录分隔符,输出时用指定符号代替换行符
NF :字段数量,共有多少字段, $NF引用最后一列,$(NF-1)引用倒数第2列
NR :行号,后可跟多个文件,第二个文件行号继续从第一个文件最后行号开始
FNR :各文件分别计数, 行号,后跟一个文件和NR一样,跟多个文件,第二个文件行号从1开始
FILENAME :当前文件名
ARGC :命令行参数的个数
ARGV :数组,保存的是命令行所给定的各参数,查看参数
(2)演示
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
[root@along ~]# cat awkdemo
hello:world
linux:redhat:lalala:hahaha
along:love:youou
[root@along ~]# awk -v FS=':' '{print $1,$2}' awkdemo #FS指定输入分隔符
hello world
linux redhat
along love
[root@along ~]# awk -v FS=':' -v OFS='---' '{print $1,$2}' awkdemo #OFS指定输出分隔符
hello---world
linux---redhat
along---love
[root@along ~]# awk -v RS=':' '{print $1,$2}' awkdemo
hello
world linux
redhat
lalala
hahaha along
love
you
[root@along ~]# awk -v FS=':' -v ORS='---' '{print $1,$2}' awkdemo
hello world---linux redhat---along love---
[root@along ~]# awk -F: '{print NF}' awkdemo
2
4
3
[root@along ~]# awk -F: '{print $(NF-1)}' awkdemo #显示倒数第2列
hello
lalala
love
[root@along ~]# awk '{print NR}' awkdemo awkdemo1
1
2
3
4
5
[root@along ~]# awk END'{print NR}' awkdemo awkdemo1
5
[root@along ~]# awk '{print FNR}' awkdemo awkdemo1
1
2
3
1
2
[root@along ~]# awk '{print FILENAME}' awkdemo
awkdemo
awkdemo
awkdemo
[root@along ~]# awk 'BEGIN {print ARGC}' awkdemo awkdemo1
3
[root@along ~]# awk 'BEGIN {print ARGV[0]}' awkdemo awkdemo1
awk
[root@along ~]# awk 'BEGIN {print ARGV[1]}' awkdemo awkdemo1
awkdemo
[root@along ~]# awk 'BEGIN {print ARGV[2]}' awkdemo awkdemo1
awkdemo1
4.3.2 自定义变量
自定义变量( 区分字符大小写)
(1)-v var=value
① 先定义变量,后执行动作print
1
2
3
4
[root@along ~]# awk -v name="along" -F: '{print name":"$0}' awkdemo
along:hello:world
along:linux:redhat:lalala:hahaha
along:along:love:you
② 在执行动作print后定义变量
1
2
3
4
[root@along ~]# awk -F: '{print name":"$0;name="along"}' awkdemo
:hello:world
along:linux:redhat:lalala:hahaha
along:along:love:you
(2)在program 中直接定义
可以把执行的动作放在脚本中,直接调用脚本 -f
1
2
3
4
5
6
[root@along ~]# cat awk.txt
{name="along";print name,$1}
[root@along ~]# awk -F: -f awk.txt awkdemo
along hello
along linux
along along
4.4 printf命令
比print更强大
4.4.1 格式
(1)格式化输出
1
printf "FORMAT", item1,item2, ...
① 必须指定FORMAT
② 不会自动换行,需要显式给出换行控制符,\n
③ FORMAT 中需要分别为后面每个item 指定格式符
(2)格式符:与item 一一对应
%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E: 显示科学计数法数值
%f :显示为浮点数,小数 %5.1f,带整数、小数点、整数共5位,小数1位,不够用空格补上
%g, %G :以科学计数法或浮点形式显示数值
%s :显示字符串;例:%5s最少5个字符,不够用空格补上,超过5个还继续显示
%u :无符号整数
%%: 显示% 自身
(3)修饰符:放在%c[/d/e/f...]之间
#[.#]:第一个数字控制显示的宽度;第二个# 表示小数点后精度,%5.1f
-:左对齐(默认右对齐) %-15s
+:显示数值的正负符号 %+d
4.4.2 演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@along ~]# awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1
---第一列显示小于20的字符串;第2列显示整数并换行
[root@along ~]# awk -F: '{printf "%20s---%u\n",$1,$3}' /etc/passwd
root---0
bin---1
---使用-进行左对齐;第2列显示浮点数
[root@along ~]# awk -F: '{printf "%-20s---%-10.3f\n",$1,$3}' /etc/passwd
root ---0.000
bin ---1.000
---使用printf做表格
[root@along ~]# awk -F: 'BEGIN{printf "username userid\n-----------------------------\n"}{printf "%-20s|%-10.3f\n",$1,$3}' /etc/passwd
username userid
-----------------------------
root |0.000
bin |1.000
4.5 操作符
4.5.1 格式
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^=
++, --
比较操作符:
==, !=, >, >=, <, <=
模式匹配符:~ :左边是否和右边匹配包含 !~ :是否不匹配
逻辑操作符:与&& ,或|| ,非!
函数调用: function_name(argu1, argu2, ...)
条件表达式(三目表达式):selector?if-true-expression:if-false-expression
注释:先判断selector,如果符合执行 ? 后的操作;否则执行 : 后的操作
4.5.2 演示
(1)模式匹配符
1
2
3
4
5
6
7
8
9
10
11
---查询以/dev开头的磁盘信息
[root@along ~]# df -h |awk -F: '$0 ~ /^\/dev/'
/dev/mapper/cl-root 17G 7.3G 9.7G 43% /
/dev/sda1 1014M 121M 894M 12% /boot
---只显示磁盘使用状况和磁盘名
[root@along ~]# df -h |awk '$0 ~ /^\/dev/{print $(NF-1)"---"$1}'
43%---/dev/mapper/cl-root
12%---/dev/sda1
---查找磁盘大于40%的
[root@along ~]# df -h |awk '$0 ~ /^\/dev/{print $(NF-1)"---"$1}' |awk -F% '$1 > 40'
43%---/dev/mapper/cl-root
(2)逻辑操作符
1
2
3
4
5
6
7
8
9
10
[root@along ~]# awk -F: '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd
root 0
bin 1
[root@along ~]# awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
root
[root@along ~]# awk -F: '!($3==0) {print $1}' /etc/passwd
bin
[root@along ~]# awk -F: '!($0 ~ /bash$/) {print $1,$3}' /etc/passwd
bin 1
daemon 2
(3)条件表达式(三目表达式)
1
2
3
[root@along ~]# awk -F: '{$3 >= 1000?usertype="common user":usertype="sysadmin user";print usertype,$1,$3}' /etc/passwd
sysadmin user root 0
common user along 1000
4.6 awk PATTERN 匹配部分
4.6.1 格式
PATTERN:根据pattern 条件,过滤匹配的行,再做处理
(1)如果未指定:空模式,匹配每一行
(2)/regular expression/ :仅处理能够模式匹配到的行,正则,需要用/ / 括起来
(3)relational expression:关系表达式,结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
(4)line ranges:行范围
startline(起始行),endline(结束行):/pat1/,/pat2/ 不支持直接给出数字,可以有多段,中间可以有间隔
(5)BEGIN/END 模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{} :仅在文本处理完成之后执行
4.6.2 演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@along ~]# awk -F: '{print $1}' awkdemo
hello
linux
along
[root@along ~]# awk -F: '/along/{print $