面试题:grep、sed、awk有何区别?
grep用于查找特定内容,适合快速过滤日志或配置文件。
sed用于修改和编辑文本,非常适合批量替换或删除操作。
awk更强大,适用于列状数据的处理,能够提取字段、统计数据或进行数学计算。
在运维工作中,我会根据不同的需求选择合适的工具:当需要简单查找时用 grep,批量修改文件时用 sed,处理复杂的日志或统计数据时使用 awk。
grep
grep主要作用:过滤来自一个文件或标准输入匹配模式内容。
除了 grep 外,还有 egrep。egrep 是 grep 的扩展,相当于 grep -E。
基本语法:grep [OPTION]... PATTERN [FILE]...
支持的正则 | 描述 |
-E,--extended-regexp | 模式是扩展正则表达式(ERE) => 字符簇、()、|或 |
-P,--perl-regexp | 模式是Perl正则表达式 => \d、\w、\s |
-i,--ignore-case | 忽略大小写 |
-w,--word-regexp | 模式匹配整个单词--- 精准匹配单词 |
-v,--invert-match | 打印不匹配的行 传说中的取反 |
输出控制 | 描述 |
-n,--line-number | 打印行号 |
-h,--no-filename | 不输出文件名 |
-o,--only-matching | 只打印匹配的内容 |
-r,--recursive | 递归目录 |
-c,--count | 统计匹配行数 |
sed
sed = 流编辑器(Stream Editor),核心作用:批量修改、替换、删除、截取文本,主打行级文本编辑,不用打开文件,命令行直接处理
sed [选项] '操作' 文件名 # 或 管道用法 命令 | sed '操作'-n:只输出匹配 / 处理过的行(默认打印所有行)-i:直接修改原文件(谨慎使用!)-e:执行多个编辑指令
替换 s/旧/新/
s/原字符串/新字符串/# 把每行第一个 a 换成 b sed 's/a/b/' test.txt # 全局替换(整行所有 a 都换,加 g) sed 's/a/b/g' test.txt # 带 / 路径替换,改用 # 当分隔符(避免冲突) sed 's#/usr#/home#g' test.txt打印指定行(搭配 -n)
# 只打印第 3 行 sed -n '3p' test.txt # 打印 2~5 行 sed -n '2,5p' test.txt # 匹配包含 root 的行并打印 sed -n '/root/p' test.txt删除行(d = delete)
不加 -i 只预览,加 -i 才真删文件
# 删除第 2 行 sed '2d' test.txt # 删除空行 sed '/^$/d' test.txt # 删除包含 # 注释的行 sed '/#/d' test.txt插入 / 追加文本
i:行前插入a:行后追加
# 在第 1 行前面加内容 sed '1i 开头文字' test.txt # 在最后一行后面加内容 sed '$a 结尾文字' test.txt # 全局替换,并直接改原文件 sed -i 's/old/new/g' test.txtawk
awk [选项] '模式{动作}' 文件名常见选项NR ( Number of Record )当前处理的行号
常见选项NF (Number of Field) 当前行的字段总数
$0当前行的整行内容
$1 $2 ...当前行的第 1、第 2… 个字段
# 打印第3行的所有字段数 awk 'NR==3{print NF}' test.txt # 打印第1行和第5行 awk 'NR==1 || NR==5' test.txt # 打印所有行号大于2的行 awk 'NR>2' test.txt
#需求:取出用户名和他的登录shell
awk -F":" '{print $1,$NF}' /etc/passwd-F":":指定分隔符为冒号:,/etc/passwd里的每一行都是用冒号分隔字段的。{print $1,$NF}:$1:代表每行的第 1 个字段(用户名)$NF:代表每行的最后一个字段(用户的默认 shell)
/etc/passwd:要处理的文件路径。
需求:取出整行内容,并显示行号
awk '{print NR,$0}' /etc/passwdawk记录行
NR 全称是Number of Record,中文叫 “记录号 / 行号”
#取 ifconfig ens160 的输出,交给 awk 处理,当读到第 2 行时,打印这一行的第 2 个字段(通常就是网卡的 IP 地址) ifconfig ens160 | awk 'NR==2{print $2}'NR:awk 处理文本时,每读一行,NR的值就会 + 1,所以它代表当前正在处理的行号。NR==2:是一个条件判断(模式),意思是 “当行号等于第 2 行的时候”。{print $2}:是满足条件时执行的动作,打印这一行的第 2 个字段。
awk模式与动作进阶
awk '$0~/正则表达式/'
以冒号为分隔符,截取/etc/passwd 里第五列(用户注释信息)是否包含字符串shutdown
awk -F":" '$5~/shutdown/' /etc/passwd例子1,有一个文档里面显示如下
练习:显示姓Zhang的人的第二次捐款金额及她的名字
awk -F"[ :]+" '$1~/^Zhang/{print $1$2,$(NF-1)}' awk.txt练习:显示Xiaoyu的名字和ID号码,并以逗号隔开
awk -F"[ :]+" '$2~/^Xiaoyu/{print $2","$3}' awk.txt练习:显示所有以41开头的ID号码的人的全名和ID号码
awk -F"[ :]+" '$3~/^41/{print $1$2$3}' awk.txt练习:取出网卡ens33/ens160的ip地址
ifconfig ens160 |sed -n '2p' |awk -F"[ ]+" '{print $3}'练习:取出常用服务端口号 思路: linux下面服务与端口信息的对应表格在/etc/services里面,所以这道题要处理/etc/services文件
awk -F"[ /]+" '$1~/^(ssh|https|ftp|rsync)$/{print $1,$2}' /etc/services|sort|uniq -c|sort -nrBEGIN模式和END模式
BEGIN设置表头
awk 'BEGIN{print "username","UID"}{print $1":"$3}' awk.txt给变量赋值方便后续做运算
echo |awk 'BEGIN{a=10}{print a}'awk 'BEGIN{a=10;print a}'awk 'BEGIN{a=10;print a}'- 只有
BEGIN块,所以只会执行一次:①a=10给变量赋初始值②print a直接打印这个值 - 结果就是输出
10,这里变量的作用是临时保存一个值,供当前步骤使用。
- 只有
echo | awk 'BEGIN{a=10}{print a}'- 执行流程分两步:① 先执行
BEGIN{a=10}:初始化变量a为10(只执行 1 次)② 再执行{print a}:因为echo给了 1 行输入,所以主处理块会执行 1 次,打印a的值10 - 这里变量
a的值,从BEGIN块传递到了后续的主处理块里。
- 执行流程分两步:① 先执行
END
- 自动初始化:awk 中未初始化的数字变量,默认值为
0,所以i一开始就是0。 - 计数逻辑:每遇到一个空行,
i++就会让i加 1,记录空行的数量。 - 结果输出:
END块在所有行处理完后执行,此时i的值就是最终的空行总数
awk支持数学运算
查看cpu的使用率
top -bn1 | awk -F"[ ,]+" 'NR==3{print $8}'第3行第8列,以多个空格逗号分隔
计算1-100的和
seq 100 > 100.txt$0整行内容代表当前处理的一整行数据,不管这一行有多少字段,$0都是完整的一行
$1第 1 个字段代表当前行按分隔符切分后的第一个字段,默认分隔符是空格 / 制表符