Linux Shell编程及自动化运维实现-5-正则、grep、sed、awk

在 Linux 自动化运维与 Shell 编程中,grep、sed、awk 被合称为「文本处理三剑客」,配合正则表达式可以实现极高效的文本过滤、替换、提取与统计工作,是运维工程师的必备核心技能。本文系统梳理正则表达式基础与三剑客的核心用法,配合大量实战示例帮助快速上手。

正则表达式基础

正则表达式(Regular Expression, RE)是一套字符匹配模式,通过特殊符号定义匹配规则,在文本中查找符合规则的内容。它是三剑客的核心能力基础,广泛应用于 grep、sed、awk,以及 MySQL、Python、Nginx 等众多技术场景。

核心概念

  • 元字符:具备特殊含义、不同于字面本身的字符,是正则表达式的核心组成


  • 行内匹配:正则默认按行匹配,只要行中包含符合规则的内容就会匹配整行


  • 分类:分为基本正则(BRE)与扩展正则(ERE),扩展正则新增了更多元字符,语法更简洁,需要工具开启对应支持


基本正则表达式元字符(BRE)

元字符含义示例与说明
^行首定位符,匹配行开头grep "^root" /etc/passwd 匹配以 root 开头的行
$行尾定位符,匹配行结尾grep "bash$" /etc/passwd 匹配以 bash 结尾的行
.匹配任意单个字符(除换行符)grep "a.c" test.txt 可匹配 abc、adc、aec 等
*匹配前一个字符 0 次或多次grep "ab*c" test.txt 可匹配 ac、abc、abbc 等
.*匹配任意长度的任意字符grep ".*" test.txt 匹配文件中所有行
[]匹配指定范围内的单个字符[lL]ove 匹配 love、Love;[a-z0-9] 匹配小写字母或数字
[^]匹配不在指定范围内的单个字符(取反)[^0-9]ove 匹配非数字开头的 ove 字符串
\转义符,取消元字符的特殊含义grep "l\." 1.txt 匹配字面量 l.
\<词首定位符,匹配单词开头grep "\<love" test.txt 匹配以 love 开头的单词
\>词尾定位符,匹配单词结尾grep "love\>" test.txt 匹配以 love 结尾的单词
()匹配稍后使用的字符的标签:3,9 s/(.*)/#\1/ 加注释
x\{m\}字符 x 连续出现 m 次grep "x\{m\}" test.txt 匹配连续 3 个 o
x\{m,\}字符 x 连续出现至少 m 次o\{5,\} 匹配至少 5 个连续 o
x\{m,n\}字符 x 连续出现 m~n 次o\{3,5\} 匹配 3 到 5 个连续 o

补充说明:^ 是「行首」,\< 是「词首」。^love 只匹配行第一个单词是 love 的行;<love 可以匹配行中任意位置以 love 开头的单词。

扩展正则表达式元字符(ERE)

扩展正则在基本正则基础上新增了更灵活的语法,使用时需要通过 grep -E(即 egrep)、sed -r 开启支持。

元字符含义示例与说明
+匹配前一个字符 1 次或多次egrep "lo+ve" test.txt 匹配 love、loove,不匹配 lve
?匹配前一个字符 0 次或 1 次egrep "lo?ve" test.txt 匹配 lve、love,不匹配 loove
a|b匹配a或b逻辑或,匹配左右任意一个表达式
()分组,将多个字符作为整体处理

高频正则示例

# 找love
grep   love    1.txt

# 以love开头
/^love/

# 以love结尾
/love$/

# l开始,一个任意字符,ve结尾
/l.ve/

# l开始,零个或多个o,ve结尾
/lo*ve/

# 大L 或者小L 开头的  ove
/[Ll]ove/

# love最后一个小写字母
/love[a-z]/

# love最后一个(不是字母或者数字),而是符号
/love[^a-zA-Z0-9]/
[root@localhost ~]# egrep  "love[^a-zA-Z0-9]" 1.txt 
love,
love?

# 所有行
/.*/
[root@localhost ~]# egrep ".*" 1.txt | wc

# 空行
/^$/

# 开头一个大写,最后2个任意字符
/^[A-Z]..$/

# 一个大写开头,0到多个小写或空格,3,最后是0-5的一个数字
/^[A-Z][a-z ]*3[0-5]/

# 0到多个小写字母,最后一个点
/[a-z]*\./

# 0到多个空格开头,一个大写,一个小写,再一个小写结尾
/^ *[A-Z][a-z][a-z]$/    

# 0到多个字母开头,非逗号,0到多个英文结尾
/^[A-Za-z]*[^,][A-Za-z]*$/

# 找个单词
/\<fourth\>/

# 找单词
/\<f.*th\>/

# 5两次2三次和一个点
/5{2}2{3}\./

# 0到多个 ,空格或tab的行
/^[ \t]*$/

# 井号开头的行
/^#/

# 有0到多个,空格或者tab开头的行,的注释行
/^[ \t]*#/

# 多个r
:1,$ s/\([Oo]ccur\)ence/\1rence/    

# 换个位置
:1,$ s/\(square\) and \(fair\)/\2 and \1/    

grep 文本过滤工具

grep 是三剑客中的「查找器」,核心能力是根据正则规则从文本中过滤出符合条件的行,是 Linux 下最常用的文本检索工具。

grep 家族与返回值

grep 有三个常用变体,适配不同场景:

  • grep:默认支持基本正则表达式


  • egrep(等价于 grep -E):支持扩展正则表达式


  • fgrep(等价于 grep -F):不解析正则,纯字面量匹配,处理速度快


命令返回值含义

  • 0:成功找到匹配内容


  • 1:未找到任何匹配内容


  • 2:文件不存在、权限不足等执行错误


grep "root" /etc/passwd
echo $?  # 输出 0,匹配成功

grep "not_exist_user" /etc/passwd
echo $?  # 输出 1,无匹配结果

grep "root" /not_exist_file
echo $?  # 输出 2,文件不存在

核心参数详解

参数功能示例
-q静默模式,不输出结果,只通过返回值判断grep -q "root" /etc/passwd 常用于 Shell 脚本条件判断
-v反向匹配,输出不包含规则的行grep -v "^#" config.conf 过滤掉注释行
-R / -r递归检索目录下所有文件grep -R "nginx" /etc/ 在 /etc 目录下递归查找 nginx
-o只输出匹配到的关键字,而非整行grep -o "root" /etc/passwd 每行输出一个匹配到的 root
-n输出结果时显示行号grep -n "root" /etc/passwd
-B N显示匹配行的前 N 行(Before)grep -B2 "error" app.log
-A N显示匹配行的后 N 行(After)grep -A5 "404" access.log
-C N显示匹配行的前后各 N 行(Context)grep -C3 "Exception" error.log
-l只输出包含匹配内容的文件名grep -rl "root" /etc/

此外扩展正则还支持两个快捷符号:

  • \w:等价于 [a-zA-Z0-9],匹配字母数字字符


  • \W:等价于 [^a-zA-Z0-9],匹配非字母数字字符


  • \b:等价于 <>,匹配单词边界


常用过滤示例

# 查找以 n 开头的行
egrep "^n" datafile.txt

# 查找以 4 结尾的行
egrep "4$" datafile.txt

# 查找包含 5. 开头后跟任意字符的行
egrep "5\.." datafile.txt

# 查找连续出现 9 个小写字母的行
egrep "[a-z]{9}" datafile.txt

# 匹配完整独立单词 north
egrep "\bnorth\b" datafile.txt

# 匹配包含 NW 或 EA 的行
egrep "NW|EA" datafile.txt

# 匹配包含 1 个及以上 3 的行
egrep "3+" datafile.txt

# 匹配包含一个或多个 no 的行
egrep "(no)+" datafile.txt

sed 流编辑器

sed(Stream EDitor)是三剑客中的「编辑器」,是一款非交互式的流编辑器,逐行处理文本并输出结果,默认不修改原文件,非常适合批量自动化修改配置文件、文本格式转换等场景。

工作原理与基础格式

工作流程

  1. 读取一行文本存入「模式空间」(临时缓冲区)


  2. 根据 sed 命令处理模式空间中的内容


  3. 处理完成后将模式空间内容输出到屏幕


  4. 读取下一行重复上述流程,直到文件末尾


两种使用格式

# 1. 命令行模式:直接写处理规则
sed [选项] '处理命令' 文件名

# 2. 脚本模式:从文件读取处理规则
sed [选项] -f 脚本文件 文件名

返回值说明

  • 正常执行时无论是否匹配到内容,返回值都是 0


  • 仅当命令存在语法错误时,返回非 0 值


正则支持

  • 默认支持基本正则表达式


  • -r 参数可支持扩展正则表达式


核心命令详解

删除命令 d

删除匹配到的行。

# 删除包含 root 的行
sed -r '/root/d' passwd

# 删除第 3 行
sed -r '3d' passwd

# 删除第 3 行到最后一行
sed -r '3,$d' passwd

# 删除最后一行
sed -r '$d' passwd

# 删除所有空行
sed -r '/^$/d' test.txt

# 删除所有 # 开头的注释行
sed -r '/^#/d' config.conf

替换命令 s

最常用的核心命令,格式为 s/原内容/替换内容/标记

# 将每行第一个 root 替换为 aofa
sed -r 's/root/aofa/' passwd

# 全局替换:将所有 root 替换为 aofa
sed -r 's/root/aofa/g' passwd

# 只替换行首的 root
sed -r 's/^root/aofa/' passwd

# & 代表匹配到的内容:在结尾两位数字后追加 .5
sed -r 's/[0-9][0-9]$/&.5/' passwd

# 反向引用:给所有 mail 前面加上 E
sed -r 's/(mail)/E\1/g' passwd

# 自定义分隔符:当内容包含 / 时,可用 # 或 @ 作为分隔符
sed -r 's#/bin/bash#/bin/zsh#g' passwd

读写文件命令 r /w

  • r:读取外部文件内容,追加到匹配行之后


  • w:将匹配到的行写入到外部文件(另存为)


# 在文件最后一行之后追加 1.txt 的全部内容
sed -r '$r 1.txt' passwd

# 在包含 root 的行之后追加 1.txt 的内容
sed -r '/root/r 1.txt' passwd

# 将 passwd 前 5 行另存为 123.txt
sed -r '1,5w 123.txt' passwd

# 将包含 root 的行另存为 root_line.txt
sed -r '/root/w root_line.txt' passwd

追加 / 插入 / 替换整行

  • a:在匹配行之后追加新行


  • i:在匹配行之前插入新行


  • c:将匹配行整体替换为新内容


# 在第 2 行之后追加一行 123
sed -r '2a123' passwd

# 在第 2 行之前插入一行 aaaaaaaa
sed -r '2iaaaaaaaa' passwd

# 将第 2 行整行替换为 new_content
sed -r '2cnew_content' passwd

# 插入多行内容,用 \ 转义换行
sed -r '2a line1\nline2\nline3' passwd

其他常用命令

  • n:读取下一行到模式空间(next),配合其他命令使用


  • !:反向选择,对不匹配的行执行命令


  • -e:多重编辑,同时执行多条 sed 命令


# 找到 root 行后,删除它的下一行
sed -r '/root/{n;d}' passwd

# 删除第 2 行以外的所有行(只保留第 2 行)
sed -r '2!d' passwd

# 多重编辑:删除1-3行,再把第4行的 adm 换成 admin
sed -r -e '1,3d' -e '4s/adm/admin/g' passwd
# 等价写法,用分号分隔多条命令
sed -r '1,3d;4s/adm/admin/g' passwd

运维实战案例

# 1. 删除 vsftpd 配置中的所有注释行
sed -ri '/^#/d' /etc/vsftpd/vsftpd.conf

# 2. 在配置文件末尾追加一行配置
sed -ri '$a\chroot_local_user=YES' /etc/vsftpd/vsftpd.conf

# 3. 修改 SELINUX 配置项的值
sed -ri '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config

# 4. 给 2-6 行添加 # 注释
sed -r '2,6s/^/#/' a.txt
# 两种等价写法
sed -r '2,6s/(.*)/#\1/' a.txt
sed -r '2,6s/.*/#&/' a.txt

# 5. sed 中调用外部 Shell 变量
var1="hello world"
sed -r "1a$var1" /etc/hosts
# 注意:调用变量必须用双引号,单引号内变量不会被解析

生产环境提示:-i 参数会直接修改原文件,建议先不加 -i 验证输出结果,确认无误后再添加该参数执行修改。

awk 文本处理语言

awk 是三剑客中功能最强大的「分析器」,它本身就是一门完整的编程语言,擅长对结构化文本进行按列提取、统计、运算与格式化输出,是日志分析、数据统计的核心利器。

工作原理与基础语法

工作流程

  1. 逐行读取文本,将整行内容存入内置变量 $0


  2. 根据字段分隔符将行拆分为多个字段,依次存入 $1, $2, $3...


  3. 执行用户定义的处理动作


  4. 读取下一行重复处理,直到文件结束


标准语法结构

awk [选项] 'BEGIN{预处理} {行处理} END{后处理}' 文件名
  • BEGIN{}:处理所有行之前执行一次,常用于初始化变量、设置分隔符


  • {}:行处理块,每读取一行就执行一次


  • END{}:处理所有行之后执行一次,常用于输出最终统计结果


基础示例:

# 以冒号分隔,打印用户名和对应 UID
awk -F: '{print $1, $3}' /etc/passwd

# 三段式完整结构示例
awk 'BEGIN{print "start"} {print $0} END{print "end"}' /etc/hosts

核心内部变量

变量含义示例
FS输入字段分隔符,默认空格awk 'BEGIN{FS=":"} {print $1}' /etc/passwd
OFS输出字段分隔符,默认空格awk 'BEGIN{OFS="---"} {print $1,$2}'
RS输入记录(行)分隔符,默认换行可自定义行分隔符实现特殊格式解析
NR当前记录号(行号),多文件连续计数awk '{print NR, $0}' file1 file2
FNR当前文件的记录号,多文件独立计数awk '{print FNR, $0}' file1 file2
NF当前行的字段总数awk -F: '{print NF, $NF}' /etc/passwd
$NF最后一个字段的内容常用于直接取每行最后一列

模式匹配与条件判断

awk 支持丰富的匹配模式,只有符合模式的行才会执行对应动作。

正则匹配

使用 ~ 表示匹配,!~ 表示不匹配。

# 匹配以 root 开头的行
awk '/^root/' /etc/passwd
awk '$0 ~ /^root/' /etc/passwd

# 第一列匹配以 root 开头
awk -F: '$1 ~ /^root/' /etc/passwd

# 第一列不包含 root 字符串
awk -F: '$1 !~ /root/' /etc/passwd

数值与字符串比较

支持 ==!=<><=>= 全套比较运算符。

# UID 等于 0 的用户行
awk -F: '$3 == 0' /etc/passwd

# UID 小于 10 的用户行
awk -F: '$3 < 10' /etc/passwd

# 默认 shell 是 /bin/bash 的用户
awk -F: '$7 == "/bin/bash"' /etc/passwd

逻辑运算与范围模式

# 逻辑与:用户名包含root 且 UID<=15
awk -F: '$1~/root/ && $3<=15' /etc/passwd

# 逻辑或:用户名包含root 或 UID<=15
awk -F: '$1~/root/ || $3<=15' /etc/passwd

# 范围模式:从包含 adm 的行到包含 lpd 的行全部输出
awk -F: '/adm/,/lpd/' /etc/passwd

awk 编程基础

变量使用

awk 支持自定义变量,无需声明可直接使用。

# -v 参数传入自定义变量
awk -v user=root -F: '$1 == user' /etc/passwd

# 调用 Shell 外部变量
name="root"
awk -F: '$1 == "'"$name"'"' /etc/passwd

条件分支

# 单分支:UID 为 0 则标记为管理员
awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd

# 双分支:统计管理员和系统用户数量
awk -F: '{if($3==0){count++} else{i++}} END{print "管理员数:"count; print "系统用户数:"i}' /etc/passwd

# 多分支:按 UID 分类用户类型
awk -F: '{
    if($3==0){print $1,"is admin"}
    else if($3>=1000){print $1,"is normal user"}
    else{print $1,"is system user"}
}' /etc/passwd

循环结构

# while 循环:将每行内容打印 10 次
awk '{i=1; while(i<=10){print $0; i++}}' passwd

# for 循环:逐列打印每行的所有字段
awk -F: '{for(i=1;i<=NF;i++) {print $i}}' passwd

# 数字循环:输出 1 到 5
awk 'BEGIN{for(i=1;i<=5;i++){print i}}'

数组

awk 数组支持关联数组,非常适合用于统计、去重场景。

# 将用户名存入数组
awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd

# 遍历数组打印所有键值
awk -F: '{user[$1]=$3} END{for(i in user){print i, user[i]}}' /etc/passwd

经典实战案例

统计系统中各类 shell 的数量

awk -F: '{shells[$NF]++} END{for(i in shells){print i, shells[i]}}' /etc/passwd

统计三类用户的数量

awk -F: '{
    if($3==0){admin++}
    else if($3>=1000){normal++}
    else{system++}
} END{
    print "管理员数量:", admin
    print "系统用户数量:", system
    print "普通用户数量:", normal
}' /etc/passwd

三目运算符简化判断

# 第7列大于4显示high,否则显示low
awk '{print ($7 > 4 ? "high "$7 : "low "$7)}' datafile

写在最后

Shell 三剑客 + 正则表达式是 Linux 文本处理的黄金组合:

  • grep 擅长快速过滤查找,精准定位目标行
  • sed 擅长批量编辑替换,自动化完成配置修改
  • awk 擅长结构化数据分析,实现统计、计算、格式化输出

SHELL脚本自动化部署LAMP环境

在线部署网校系统

#!/bin/bash
# 定义数据库密码变量
Mysql_Pass=123

# 系统更新(已注释禁用)
#yum update

# 安装 EPEL 扩展软件源
yum -y install epel-release

# 安装基础环境工具
yum -y install bash-completion vim wget
systemctl restart firewalld
systemctl enable firewalld

setenforce 0

# 防火墙规则配置:开放 HTTP、HTTPS 服务及 8080 端口
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload

# 安装 LAMP 运行环境(Apache + PHP + MariaDB)
yum -y install httpd
yum -y install \
php php-cli \
php-curl \
php-fpm \
php-intl \
php-mcrypt \
php-mysql \
php-gd \
php-mbstring \
php-xml \
php-dom

yum -y install mariadb-server mariadb
yum -y install http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/m/mod_xsendfile-0.12-10.el7.x86_64.rpm

# Apache 服务配置
rm -rf /etc/httpd/conf.d/welcome.conf
# 修改 Apache 监听端口为 8080(当前已注释禁用)
#sed -ri 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf
systemctl enable httpd

# MariaDB 数据库初始化
systemctl start mariadb
systemctl enable mariadb

mysqladmin -uroot password "$Mysql_Pass"
mysql -uroot -p"$Mysql_Pass" -e "create database edusoho"

# PHP 运行参数配置
sed -ri 's/post_max_size = 8M/post_max_size = 1024M/' /etc/php.ini
sed -ri 's/memory_limit = 128M/memory_limit = 1024M/' /etc/php.ini
sed -ri 's/upload_max_filesize = 2M/upload_max_filesize = 1024M/' /etc/php.ini
sed -ri 's#;date.timezone =#date.timezone = Asia/ShangHai#' /etc/php.ini
systemctl start php-fpm
systemctl enable php-fpm

# 下载并部署 EduSoho 程序
wget http://download.edusoho.com/edusoho-7.5.12.tar.gz
tar xf edusoho-7.5.12.tar.gz
cp -rf edusoho /var/www/
chown -R apache.apache /var/www/edusoho/

rm -rf /var/www/html/index.html
sed -ri 's#DocumentRoot "/var/www/html"#DocumentRoot "/var/www/edusoho/web"#' /etc/httpd/conf/httpd.conf 
cat >>/etc/httpd/conf/httpd.conf <<EOF
<Directory "/var/www/edusoho/web">
AllowOverride All
Require all granted
</Directory>
EOF

systemctl restart httpd
systemctl restart php-fpm

三者经常通过管道联合使用,配合 Shell 脚本可以实现复杂的自动化运维任务,大幅提升批量处理文本的效率。熟练掌握三剑客,是 Linux 运维进阶的必经之路。


🙋 学习路上不孤单,有坑一起填!



卡在参数调试、命令打架、功能没反应、资源失效?其他问题?直接戳我,也可以进群和同好交流!



📱 个人QQ:3838586495    👥 交流Q群:1094091455    📮 邮箱:leyan2504@163.com



内容帮你省了大把踩坑时间?可以文末小小打赏鼓励一波,也欢迎安利给身边学习的朋友~



✨ 欢迎来评论区「交作业」:分享你的配置思路、提出疑难问题;评论区正确填写邮箱,不错过任何人的解答回复!


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇