Linux 文本三剑客
2021-05-19 约 3073 字
预计阅读 7 分钟
Linux 文本三剑客
awk、grep、sed 是 linux 操作文本的三大利器,合称文本三剑客,也是必须掌握的 linux 命令之一。
三者的功能都是处理文本,但侧重点各不相同,其中属 awk 功能最强大,但也最复杂。
grep 更适合单纯的查找或匹配文本。
sed 更适合编辑匹配到的文本。
awk 更适合格式化文本,对文本进行较复杂格式处理。
grep
介绍
grep 全称是 Global Regular Expression Print。grep 命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来(匹配到的标红)。
egrep = grep -E:扩展的正则表达式 (除了< , > , \b 使用其他正则都可以去掉\)
命令格式:grep [option] pattern file…
命令参数
参数
释义
-A<显示行数>
除了显示符合范本样式的那一列之外,并显示该行之后的内容。
-B<显示行数>
除了显示符合样式的那一行之外,并显示该行之前的内容。
-C<显示行数>
除了显示符合样式的那一行之外,并显示该行之前后的内容。
-c
统计匹配的行数
-e
实现多个选项间的逻辑 or 关系
-E
扩展的正则表达式
-f FILE
从 FILE 获取 PATTERN 匹配
-F
相当于 fgrep,搜索字符串而不会匹配正则
-i –ignore-case
忽略字符大小写的差别。
-n
显示匹配的行号
-o
仅显示匹配到的字符串
-q
静默模式,不输出任何信息
-s
不显示错误信息。
-v
显示不被 pattern 匹配到的行,相当于[^] 反向匹配
-w
匹配 整个单词
grep 实战演示
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
[ root@along ~] # cat test
aaa
bbbbb
AAAaaa
BBBBASDABBDA
[ root@along ~] # grep -A2 b test
bbbbb
AAAaaa
BBBBASDABBDA
[ root@along ~] # grep -B1 b test
aaa
bbbbb
[ root@along ~] # grep -C1 b test
aaa
bbbbb
AAAaaa
[ root@along ~] # grep -c b test
2
[ root@along ~] # grep -e AAA -e bbb test
bbbbb
AAAaaa
[ root@along ~] # grep -in b test
2:bbbbb
4:BBBBASDABBDA
[ root@along ~] # grep -o ASDA test1
ASDA
[ root@along ~] # grep -q aa test1
[ root@along ~] # grep -v aaa test1
bbbbb
BBBBASDABBDA
[ root@along ~] # grep -w aaa test1
aaa
[ root@along ~] # cat grep.txt
aaa
[ root@along ~] # grep -f grep.txt test
aaa
AAAaaa
sed
介绍
sed 英文全称是 stream editor,是一种流编辑器,它一次处理一行内容。
处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace ),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。
除非使用重定向存储输出或-i,文件内容才会改变,这个参数可以用来操作文件。
命令格式:sed [options] ‘[地址定界] command’ file(s)
常用选项 options
参数
释义
-n
不输出模式空间内容到屏幕,即不自动打印,只打印匹配到的行
-e
多点编辑,对每行处理时,可以有多个 Script
-f
把 Script 写到文件当中,在执行 sed 时-f 指定文件路径,如果是多个 Script,换行写
-r
支持扩展的正则表达式
-i
直接将处理的结果写入文件
-i.bak
在将处理的结果写入文件之前备份一份
常用选项 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
地址定界
地址
释义
不给地址
对全文处理
#
指定的行
/pattern/
被此处模式所能够匹配到的每一行
#,#
从#行,到#行
#,+n
从#行开始,一直到向下的 n 行
/pat1/,/pat2/
从第一次被 pat1 匹配到的行开始,到第一次被 pat2 匹配到的行结束,中间的所有行
#,/pat1/
从#行开始,到第一次被 pat1 匹配到的行结束,中间的所有行
~
步进,指定起始行及步长
1~2
所有奇数行
2~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
编辑命令 command
参数
释义
d
删除模式空间匹配的行,并立即启用下一轮循环
p
打印当前模式空间内容,追加到默认输出之后
a
在指定行后面追加文本,支持使用\n 实现多行追加
i
在行前面插入文本,支持使用\n 实现多行追加
c
替换行为单行或多行文本,支持使用\n 实现多行追加
w
保存模式匹配的行至指定文件
r
读取指定文件的文本至模式空间中匹配到的行后
=
为模式空间中的行打印行号
!
模式空间中匹配行取反处理
s///
查找替换,支持使用其它分隔符,如:s@@@,s###。加 g 表示行内全局替换
编辑演示
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
awk
介绍
awk 是 Aho Weinberger kernaighan 三个人的首字母缩写
awk 是一种编程语言,用于在 linux/unix 下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。
支持用户自定义函数和动态正则表达式等先进功能,是 linux/unix 下的一个强大编程工具。
可以在命令行中使用,但更多是作为脚本来使用
awk 有很多内建的功能,比如数组、函数等。
语法
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 ...
常用命令选项
选项
释义
-F fs
fs 指定输入分隔符,fs 可以是字符串或正则表达式,如-F:
-v var=value
赋值一个用户定义变量,将外部变量传递给 awk
-f scripfile
从脚本文件中读取 awk 命令
内置变量
内置变量
释义
FS
输入字段分隔符,默认为空白字符
OFS
输出字段分隔符,默认为空白字符
RS
输入记录分隔符,指定输入时的换行符,原换行符仍有效
ORS
输出记录分隔符,输出时用指定符号代替换行符
NF
字段数量,共有多少字段, $NF引用最后一列,$(NF-1)引用倒数第 2 列
NR
行号,后可跟多个文件,第二个文件行号继续从第一个文件最后行号开始
FNR
各文件分别计数, 行号,后跟一个文件和 NR 一样,跟多个文件,第二个文件行号从 1 开始
FILENAME
当前文件名
ARGC
命令行参数的个数
ARGV
数组,保存的是命令行所给定的各参数,查看参数
实战演示
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
自定义变量
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
统计分析
where 条件过滤
1
2
3
4
# select * from table;
awk 1 table_file
# select * from table where cost > 100;
awk '$2>100' table_file
对某个字段去重,或者按记录去重
1
2
3
4
# select distinct(date) from table;
awk '!a[$3]++{print $3}' table_file
# select distinct(*) from table;
awk '!a[$0]++' table_file
记录按序输出
1
2
# select id from table order by id;
awk '{a[$1]}END{asorti(a);for(i=1;i<=length(a);i++){print a[i]}}' table_file
取前多少条记录
1
2
3
# select * from table limit 2;
awk 'NR<=2' table_file
awk 'NR>2{exit}1' table_file # performance is better
分组求和统计,关键词:group by、having、sum、count
1
2
# select id, count(1), sum(cost) from table group by id having count(1) > 2;
awk '{a[$1]=a[$1]==""?$2:a[$1]","$2}END{for(i in a){c=split(a[i],b,",");if(c>2){sum=0;for(j in b){sum+=b[j]};print i"\t"c"\t"sum}}}' table_file
模糊查询
1
2
3
4
5
6
# select name from table where name like 'wang%';
awk '$2 ~/^wang/{print $2}' table_file
# select addr from table where addr like '%bei';
awk '/.*bei$/{print $3}' table_file
# select addr from table where addr like '%bei%';
awk '$3 ~/bei/{print $3}' table_file
多表 join 关联查询
1
2
# select a._ , b._ from table a inner join table b on a.id = b.id and b.id = 2;
awk 'ARGIND==1{a[$1]=$0;next}{if(($1 in a)&&$1==2){print a[$1]"\t"$2"\t"$3}}' table_file table_file
多表 union all
1
2
3
4
# select a._ from table a union all select b._ from table b;
awk 1 table_file table_file
# select a._ from table a union select b._ from table b;
awk '!a[$0]++' table_file table_file
随机抽样统计,关键词:order by rand()
1
2
# select * FROM table ORDER BY RAND() LIMIT 2;
awk 'BEGIN{srand();while(i<2){k=int(rand()*10)+1;if(!(k in a)){a[k];i++}}}(NR in a)' table_file
awk 还支持 if else while for do while 自定义函数.awk 脚本.awk