shell编程之文本三剑客grep、sed、awk
文章目录
- 前言
- 1、grep
- 1.1 概述
- 1.2 案例
- 2、sed
- 2.1 概述
- 2.2 案例
- 2.2.1 输出文本
- 2.2.2 删除文本
- 2.2.3 替换文本
- 2.2.4 迁移文本
- 2.2.5 使用脚本编辑文件
- 3、awk
- 3.1 概述
- 3.2 命令格式
- 3.3 实战案例
- 3.3.1 文本
- 3.3.2 内置变量
- 3.3.3 awk运算
- 3.3.4 模糊匹配
- 3.3.5 比较符号
- 3.3.6 逻辑运算
- 3.3.7 awk结合语句
前言
Shell编程中的文本三剑客(grep、sed、awk)是Linux/Unix环境下最强大的文本处理工具组合,各自擅长不同的文本处理场景
grep
- 功能:文本过滤工具,主要用于搜索匹配特定模式的行
- 应用场景:日志过滤、配置文件检查
sed
- 功能:流编辑器,擅长行级文本编辑
- 工作流程:读取→执行→显示循环处理每行文本
awk
- 功能:文本分析工具,擅长列处理和格式化输出
- 应用场景:数据统计、报表生成
三者的典型配合:先用grep筛选目标行,再用sed进行编辑处理,最后用awk格式化输出和分析
1、grep
1.1 概述
核心功能
- 文本搜索:在文件或输入流中匹配指定模式(支持正则表达式)
- 模式筛选:支持正向/反向匹配、整词/整行匹配
- 上下文展示:可显示匹配行前后若干行内容(调试日志场景常用)
- 递归搜索:支持目录层级遍历搜索
基础语法
grep [选项] 模式 [文件...]## 当不指定文件时,默认从标准输入读取数据
常用选项分类
-i 忽略大小写
-v 反向匹配
-o 只输出匹配内容
-n 显示行号
-c 统计匹配行数
--include 指定文件类型
--exclude 排除特定文件
-r 递归搜索目录
-A n 显示匹配行后n行
-B n 显示匹配行前n行
-C n 显示匹配行前后各n行
1.2 案例
## 筛选关键字在.log 文件
grep "error" /var/log/vmware-network.log
## 忽略大小写
grep -i "the" demo
## 显示apple出现的行数
grep -c apple sg
## 显示不是apple的内容
grep -v apple sg
## 只显示匹配内容
ifconfig | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+'
## 只搜索.txt文件里的apple
grep -r --include="*.txt" "apple" ./
## 搜索除.txt文件之外的文件的apple
grep -r --exclude="*.txt" "apple" ./
## 匹配行后3行
grep -A 3 "apple" sg
## 匹配行前3行
grep -B 3 "banana" sg
## 匹配行前后各3行
grep -C 3 "pear" sg
2、sed
2.1 概述
sed是一个强大而简单的文本解析转换工具,可以读取文本,并根据指定的条件对文本内容进行编辑(删除、替换、添加、移动等),最后输出所有行或者仅输出处理的某些行
sed 的工作流程主要包括读取、执行和显示三个过程。
- 读取: sed 从输入流(文件、管道、标准输入)中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)
- 执行: 默认情况下,所有的 sed 命令都在模式空间中顺序地执行,除非指定了行的地址,否则 sed 命令将会在所有的行上依次执行
- 显示: 发送修改后的内容到输出流。在发送数据后,模式空间将会被清空在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完
选项 含义
-e 进行多次编辑
-n 取消默认输出
-f 指定sed文件名
-i 直接在源文件中修改
-r 使用扩展正则表达式命令动作 含义
p 打印输出
d 删除指定行
i 在指定行之前插入内容
a 在指定行后面插入内容
c 替换指定行所有内容
s 搜索替换
2.2 案例
2.2.1 输出文本
## 输出demo所有内容
sed -n 'p' demo
## 输出第三行
sed -n '3p' demo
## 输出3~5行
sed -n '3,5p' demo
## 输出所有奇数行
sed -n 'p;n' demo
## 输出所有偶数行
sed -n 'n;p' demo
## 输出第 1~5 行之间的奇数行(第 1、3、5 行)
sed -n '1,5{p;n}' demo
## 输出第 10 行至文件尾之间的偶数行
sed -n '10,${n;p}' demo
## 输出包含the的行
sed -n '/the/p' demo
## 输出包含the的行号
sed -n '/the/=' demo
## 输出以PI开头的行
sed -n '/^PI/p' demo
## 输出以数字结尾的行
sed -n '/[0-9]$/p' demo
## 输出包含单词wood的行
sed -n '/\<wood\>/p' demo
2.2.2 删除文本
nl 命令用于计算文件的行数
## 删除第三行
nl demo | sed '3d'
## 删除3~5行
nl demo | sed '3,5d'
删除包含cross的行
nl demo |sed '/cross/d'
## 删除小写字母开头的行
sed '/^[a-z]/d' demo
## 删除以"."结尾的行
sed '/\.$/d' demo
## 删除所有空行
sed '/^$/d' demo
2.2.3 替换文本
## 将每行的第一个the换成THE
sed 's/the/THE/' demo
## 将每行第二个l换成L
sed 's/l/L/2' demo
## 将文件中所有the替换为THE
sed 's/the/THE/g' demo
## 将文件所有o删除
sed 's/o//g' demo
## 每行行首插入#
sed 's/^/#/' demo
## 包含the的行每行行首插入#
sed '/the/s/^/#/' demo
## 每行行尾插入EOF
sed 's/$/EOF/' demo
## 将第3~5行中所有the替换成THE
sed '3,5s/the/THE/g' demo
## 将包含the的所有行o替换成O
sed '/the/s/o/O/g' demo## 修改配置文件中 禁用模式改为强制模式
sed -i.bak 's/SELINUX=disabled/SELINUX=enable/' /etc/selinux/config
2.2.4 迁移文本
- H:复制到剪贴板
- g/G:将剪贴板中的数据覆盖/追加至指定行
- w:保存为文件
- r:读取指定文件
- a:追加指定内容
- i:忽略大小写
## 将包含the的行迁移至行尾
sed '/the/{H;d};$G' demo
## 将第 1~5 行内容转移至第 17 行后
sed '1,5{H;d};17G' demo
## 将包含the 的行另存为文件 out.file
sed '/the/w out.file' demo
## 将文件sg 的内容添加到包含 the 的每行以后
sed '/the/r sg' demo
## 在第 3 行后插入一个新行,内容为New
sed '3aNew' demo
## 在包含the 的每行后插入一个新行,内容为 New
sed '/the/aNew' demo
## 在第 3 行后插入多行内容,中间的\n 表示换行
sed '3aNew1\nNew2' demo
2.2.5 使用脚本编辑文件
## 将第 1~5 行内容转移至第 16 行后
sed '1,5{H;d};16G' demo
## 可以用脚本方式来实现
## 创建文件
vim ml
1,5H
1,5d
16G
## 执行文件里的命令
sed -f ml demo
3、awk
3.1 概述
AWK 是一种处理文本文件的语言,是一个强大的文本分析工具
- 它是专门为文本处理设计的编程语言,也是行处理软件,通常用于扫描、过滤、统计汇总工作
- 数据可以来自标准输入也可以是管道或文件
工作原理
- 逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令
- 将一行分成多个""字段"然后再进行处理
- 执行结果可以通过print的功能将字段数据打印显示
工作流程
1、开始执行BEGIN模块命令
2、读入数据—Read
3、对读入的数据执行body块中的命令—Execute
4、重复2、3操作指导文件结尾—Repeat
5、执行END模块命令
3.2 命令格式
格式:awk关键字 选项 命令部分 '{xxxx}' 文件名
- FS:指定每行文本的字段分隔符,默认为空格或制表位
- NF:当前处理的行的字段个数。在执行过程中对应于当前的字段数,NF:列的个数
- NR:当前处理的行的行号(序数)。 在执行过程中对应于当前的行号
- $0:当前处理的行的整行内容
- $n:当前处理行的第 n 个字段(第 n 列)。比如: $1 表示第一个字段,$2 表示第二个字段
- FILENAME:被处理的文件名(当前输入文件的名)
- FNR 各文件分别计数的行号
- OFS 输出字段分隔符(默认值是一个空格)
- ORS 输出记录分隔符(默认值是一个换行符)
- RS:行分隔符。awk从文件上读取资料时,将根据Rs的定义把资料切割成许多条记录, 而awk一次仅读入一条记录,以进行处理。默认值是" \n’
3.3 实战案例
3.3.1 文本
cat /etc/passwd | head -10 > zz
## 打印zz里的内容
awk '{print}' zz
## 打印zz里打第一列,默认空格/tab建分割
awk '{print $1}' zz
## 以:分割,打印第五列内容
awk -F: '{print $5}' zz
## 以x分割,打印第一列内容
awk -Fx '{print $1}' /etc/passwd
## 打印第一、二列
awk '{print $1 $2}' zz1
## 第一和第二列中间加一个空格,用双引号引起来
awk '{print $1""$2}' zz1
## 逗号默认空格效果
awk '{print $1,$2}' zz1
## 制表符作为分隔符输出
awk -F: '{print $1"\t"$2}' /etc/passwd
## 定义多个分隔符
awk -F[:/] '{print $9}' zz
3.3.2 内置变量
常用的内置变量
- $1:代表第一列
- $2:代表第二列
- $0:代表整行
- NF:一行的列数
- NR:行数
## 打印包含root的行
awk -F: '/root/{print $0}' zz
## 打印包含root的行的第一列
awk -F: '/root/{print $1}' zz
## 打印包含root的行的第一列和第六列
awk -F: '/root/{print $1,$6}' zz
## 打印每一行的列数
awk -F[:/] '{print NF}' zz
## 显示行号
awk -F[:/] '{print NR}' zz
## 显示行号和整行内容
awk -F: '{print NR,$0}' zz
## 打印第二行
awk -F: 'NR==2' /etc/passwd
## 打印第二行的第一列
awk -F: 'NR==2{print $1}' /etc/passwd
## 打印最后一列
awk -F: '{print $NF}' /etc/passwd
## 打印总行数
awk 'END{print NR}' /etc/passwd
## 打印最后一行
awk 'END{print $0}' /etc/passwd
## 当前行有几列
awk -F: '{print "当前行有"NF"列"}' zz
## 第几行有几列
awk -F: '{print "第"NR"行有"NF"列"}' /etc/passwd
## 本机ip
ifconfig ens33 | awk '/netmask/{print "本机的ip地址是"$2}'
## 接受字节数
ifconfig ens33 | awk '/RX p/{print $5"字节"}'
## 根分区可用量
df -h | awk 'NR==2{print $4}'
## FS定义以冒号分割
awk 'BEGIN{FS=":"}{print $1}' pass.txt
## OFS定义输出以---分割
awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}' pass.txt
## FNR读取文件记录数,新的文件重新开始计数
awk '{print FNR,$0}' /etc/resolv.conf /etc/hosts
## NR读取文件行号,不重新计数
awk '{print NR,$0}' /etc/resolv.conf /etc/hosts
## RS指定冒号为换行符
awk 'BEGIN{RS=":"}{print $0}' /etc/passwd
## ORS输出行之间定义以空格分割
awk 'BEGIN{ORS=" "}{print $0}' /etc/passwd
3.3.3 awk运算
awk 'BEGIN{x=10;print x+1}'
awk 'BEGIN{x=10;x++;print x}'
awk 'BEGIN{print x+1}'
awk 'BEGIN{print 2.5+3.5}'
awk 'BEGIN{print 2-1}'
awk 'BEGIN{print 3*4}'
awk 'BEGIN{print 3**2}'
awk 'BEGIN{print 2^3}'
awk 'BEGIN{print 1/2}'
3.3.4 模糊匹配
## 冒号分割,包含root打印出来
awk -F: '/root/' /etc/passwd
## 冒号分割,第一列包含ro打印处理
awk -F: '$1~/ro/' /etc/passwd
## 冒号分割,第七列不包含nologin的打印出来第一列和第七列
awk -F: '$7!~/nologin/{print $1,$7}' /etc/passwd
3.3.5 比较符号
比较符号:== != <= >= < >
## 打印行数为5
awk 'NR==5{print}' /etc/passwd
## 打印行数小于5
awk 'NR<5' /etc/passwd
## 打印第三列为0的行
awk -F: '$3==0' /etc/passwd
## 打印第一列为root的行
awk -F: '$1=="root"' /etc/passwd
## 打印第三列大于等于1000的行
awk -F: '$3>=1000' /etc/passwd
3.3.6 逻辑运算
- && 要求所有条件都为真时才为真,否则为假
- || 只要有一个条件为真就为真,全为假时才为假
awk -F: '$3<10 || $3>=1000' /etc/passwd
awk -F: '$3>10 && $3<1000' /etc/passwd
awk -F: 'NR>4 && NR<10' /etc/passwd
3.3.7 awk结合语句
## 第三列小于10的打印整行
awk -F: '{if($3<10){print $0}}' /etc/passwd
## 第三列小于10的打印第三列,否则打印第一列
awk -F: '{if($3<10){print $3}else{print $1}}' /etc/passwd
## 结合数组和for循环
awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a){print i,a[i]}}'
## 统计httpd访问日志中每个ip出现的次数
awk '{a[$1]+=1;} END {for(i in a){print a[i]" "i;}}' /var/log/httpd/access_log | sort -r
awk '{ip[$1]++;}END{for(i in ip){print ip[i],i}}' /var/log/httpd/access_log | sort -r