Linux正则表达式与三剑客全攻略

Linux正则表达式与三剑客全攻略

一、概述

本文系统覆盖Linux正则表达式(基础/扩展/Perl/括号表达式)、三剑客(grep、Sed、Awk)及Linux特殊符号(引号、重定向、通配符)的全量知识点,包含正则匹配、文本处理、特殊符号应用、磁盘故障排查等核心内容。既适合运维新手从零入门,通过step-by-step实操掌握Linux文本处理与命令行核心技能,也可作为资深运维的复习参考,解决日志过滤、配置文件修改、数据提取、统计分析、脚本编写等日常工作场景。

二、核心知识点

2.1 正则表达式核心认知

2.1.1 正则分类与适用场景

正则类型 核心符号 支持工具 适用场景
基础正则(BRE) ^ $ ^$ . \ * [] [^] .* grep、sed(默认)、awk 简单文本过滤、日志匹配
扩展正则(ERE) `+ () {} ?` egrep、grep -E、sed -r、awk
Perl正则(PRE) \d \s \w \D \S \W grep -P 快捷匹配(数字、空格、单词)
括号表达式(POSIX) [:alnum:] [:alpha:] [:digit:] [:blank:] grep、sed、awk 标准化字符集匹配(跨locale兼容)

2.1.2 基础正则核心符号(必掌握)

符号 含义 优先级 核心用途
^ 匹配行开头 ★★★★★ 过滤以指定字符开头的行(如^root匹配root开头的行)
$ 匹配行结尾 ★★★★★ 过滤以指定字符结尾的行(如8$匹配以8结尾的行)
^$ 匹配空行 ★★★★★ 排除配置文件空行、日志空行
. 匹配任意单个字符(不匹配空行) ★★★★☆ 模糊匹配单个字符(如oldb.y匹配oldboy、oldbey)
\ 转义字符 ★★★★☆ 取消特殊符号含义(如\.匹配实际的点号)
* 前一个字符出现0次或多次 ★★★☆☆ 匹配重复字符(如0*匹配0次或多次0)
.* 匹配所有字符(贪婪匹配) ★★★★★ 匹配任意内容(如.*am匹配到am为止的所有内容)
[] 匹配括号内任意单个字符 ★★★★★ 限定匹配范围(如[0-9]匹配数字、[a-Z]匹配大小写字母)
[^] 排除括号内字符 ★★★☆☆ 反向匹配(如[^abc]匹配除a、b、c外的字符)

2.1.3 扩展正则核心符号(必掌握)

符号 含义 优先级 核心用途
+ 前一个字符出现1次或多次 ★★★★★ 匹配连续重复字符(如0+匹配连续1个及以上0)
` ` 逻辑“或” ★★★★☆
() 分组(整体匹配/后向引用) ★★★★★ 组合匹配、字段提取(如`(tree
{n,m} 前一个字符出现n到m次 ★★★☆☆ 精确控制重复次数(如0{3,5}匹配3-5个连续0)
? 前一个字符出现0次或1次 ★★☆☆☆ 可选字符匹配(如go?d匹配gd或god)

2.1.4 Perl正则快捷符号(常用)

符号 等价于 含义 核心用途
\d [0-9] 匹配数字 快速提取数字(如日志中的IP、端口)
\s [\t\r\n\f ] 匹配空字符(空格、制表符等) 匹配空白内容
\w [0-9a-zA-Z_] 匹配单词字符(数字、字母、下划线) 提取单词、用户名等
\D [^0-9] 匹配非数字 排除数字内容
\S [^[:space:]] 匹配非空字符 排除空白内容
\W [^0-9a-zA-Z_] 匹配非单词字符 排除单词字符

2.1.5 括号表达式(POSIX标准,了解)

表达式 等价于 含义 核心用途
[:alnum:] [0-9a-zA-Z] 字母数字字符 跨locale兼容匹配字母和数字
[:alpha:] [a-zA-Z] 字母字符 匹配大小写字母
[:digit:] [0-9] 数字字符 匹配0-9数字
[:blank:] [ \t] 空白字符(空格、制表符) 匹配可见空白
[:cntrl:] - 控制字符(ASCII 000-037、177) 匹配控制字符(如DEL)

2.2 三剑客核心认知

2.2.1 三剑客功能对比(选型指南)

工具 核心优势 擅长场景 不擅长场景
grep/egrep 过滤速度最快,正则匹配简洁 日志过滤、内容查找、条件筛选 字段提取、批量修改文件
Sed 支持行定位、替换、删除、后向引用 配置文件修改、行级批量处理、简单字段提取 复杂列操作、统计计算
Awk 强大的取行取列、统计计算、逻辑判断 字段提取、数据统计、格式整理、多条件筛选 大文件替换(效率低于Sed)

2.2.2 Sed命令核心认知

  • 定义:Stream Editor(流编辑器),用于文本的查找、替换、删除、新增、字段提取等操作,不默认修改原文件;

  • 核心优势:支持正则匹配、行号定位、批量处理、后向引用,适合大文件和自动化脚本;

  • 命令格式sed [选项] '条件 动作' 文件

  • 常用选项

    • -n:取消默认输出(仅显示匹配内容);
    • -r:支持扩展正则(无需转义+|(){}?);
    • -i:直接修改原文件(危险,建议先备份);
    • -i.bak:修改前备份原文件(生成.bak备份文件,推荐生产环境使用);
  • 核心动作

    动作 含义 核心用途
    p 打印匹配内容 查找并显示指定行/匹配内容
    d 删除匹配内容 删除空行、注释行、指定行
    s/旧值/新值/g 替换内容(g表示全局替换) 批量修改配置参数、替换字符串
    a 在匹配行后新增内容 新增配置项、注释
    i 在匹配行前插入内容 插入说明、配置模板
    c 替换整行内容 批量替换指定行的全部内容
  • 后向引用:通过正则分组()捕获字段,再通过\数字引用分组内容,实现字段提取、重组(需配合sed -r)。

2.2.3 Awk命令核心认知

  • 定义:一门处理文本的单行脚本语言,以“行”为处理单位,支持复杂的取行取列、统计计算、逻辑判断;

  • 核心优势:取列能力强、支持自定义分隔符、可实现统计求和、多条件筛选,适合结构化文本处理;

  • 命令格式awk [选项] '条件{动作}' 文件

  • 常用选项

    • -F:指定字段分隔符(默认以空白字符/连续空白字符/tab分隔);
  • 核心变量

    变量 含义 核心用途
    NR 记录号(行号) 取指定行、行范围
    NF 每行的字段数 取最后一列($NF)、倒数第N列($(NF-N)
    $0 整行内容 输出整行
    $n 第n列内容(n为数字) 取指定列(如$1取第1列、$3取第3列)
  • 常用运算符

    运算符 含义 示例
    == 等于 $3==1000(第3列等于1000)
    != 不等于 $1!="root"(第1列不等于root)
    > 大于 $3>1000(第3列大于1000)
    >= 大于等于 $3>=1000(第3列大于等于1000)
    < 小于 $3<1000(第3列小于1000)
    <= 小于等于 $3<=1000(第3列小于等于1000)
    && 并且 $3>1000 && $1~"oldboy"(第3列大于1000且第1列包含oldboy)
    ` `
  • 匹配符

    • ~:包含匹配(如$4~ /^[01]/表示第4列以0或1开头);
    • !~:不包含匹配(如$1!~ /root/表示第1列不包含root)。

2.3 Linux特殊符号核心认知

2.3.1 引号系列(字符串处理)

引号类型 核心特性 适用场景 示例
单引号(' ' 所见即所得,不解析任何特殊符号 需原样输出字符串(含变量、命令) echo '$(whoami) $UID' → 输出$(whoami) $UID
双引号(" " 解析变量($)、命令替换($(...)),不解析通配符({} 需保留变量 / 命令结果,不扩展文件名 echo "当前用户: $(whoami), UID: $UID" → 输出当前用户: root, UID: 0
不加引号 解析变量、命令替换、通配符 需扩展文件名、批量操作 echo oldboy{1..3} → 输出oldboy1 oldboy2 oldboy3
反引号(``````) 优先执行内部命令,返回执行结果(等价于$(...) 命令嵌套执行 echo "当前目录: pwd" → 输出当前目录: /root

2.3.2 重定向符号系列(IO流控制)

符号 含义 简写 应用场景
1> 标准输出重定向(清空文件后写入) > 创建文件、覆盖写入内容
1>> 标准输出追加重定向(写入文件末尾) >> 日志追加、配置文件补充
2> 标准错误输出重定向(清空后写入错误信息) - 单独捕获错误信息
2>> 标准错误追加重定向(错误信息追加到文件) - 持续捕获错误日志
>> 文件 2>&1 标准输出+错误输出合并追加重定向 - 脚本/定时任务日志(完整记录结果)
&>> 文件 标准输出+错误输出合并追加重定向 - 简化写法,同>> 文件 2>&1
</0< 标准输入重定向 - 搭配xargstr等命令读取文件
<</<<< here-document(多行输入重定向) - 批量写入多行内容到文件

2.3.3 通配符系列(文件匹配)

符号 含义 核心用途 示例
* 匹配任意长度字符(含空字符) 批量匹配文件名 ls *.log → 匹配所有.log后缀文件
? 匹配任意单个字符 精确长度文件名匹配 ls /bin/?? → 匹配/bin目录下2个字符的命令
{} 生成序列/枚举 批量创建文件、备份 touch oldboy{1..5}.txt → 创建5个文件;cp oldboy.txt{,.bak} → 备份文件
[] 匹配括号内任意单个字符 限定字符范围匹配 ls oldboy[135].txt → 匹配oldboy1/3/5.txt
[^]/[!] 匹配括号外任意单个字符 反向匹配文件名 ls oldboy[^0-9].txt → 匹配非数字结尾的文件

2.4 磁盘故障核心认知(补充场景)

2.4.1 故障场景:No space left on device

  • 核心现象:系统提示“磁盘空间不足”,无法创建文件、写入日志;
  • 排查方向
    1. 磁盘空间满(df -h查看);
    2. inode节点耗尽(df -i查看);
    3. 文件已删除但进程未释放(lsof | grep delete查看);
  • 解决思路:删除大文件/无用文件、释放占用进程、扩展磁盘空间。

三、步骤/命令

3.1 正则表达式实战命令

3.1.1 基础正则实操(grep命令)

# 环境准备:创建测试文件
cat > re.txt << EOF
I am oldboy teacher!
I teach linux.
I like badminton ball ,billiard ball and chinese chess!
my blog is http://oldboy.blog.51cto.com
our size is http://blog.oldboyedu.com
my qq is 49000448
not 4900000448.
my god ,i am not oldbey,but OLDBOY!
EOF

# 1. 匹配以my开头的行(^用法)
grep '^my' re.txt
# 输出:my blog is http://oldboy.blog.51cto.com、my qq is 49000448、my god ,i am not oldbey,but OLDBOY!

# 2. 匹配以8结尾的行($用法)
grep '8$' re.txt
# 输出:my qq is 49000448

# 3. 排除空行(^$用法)
grep -v '^$' /etc/ssh/sshd_config
# 输出:/etc/ssh/sshd_config中所有非空行

# 4. 匹配包含oldb+任意字符+y的行(.用法)
grep 'oldb.y' re.txt
# 输出:I am oldboy teacher!、my god ,i am not oldbey,but OLDBOY!

# 5. 匹配以点号结尾的行(\转义用法)
grep '\.$' re.txt
# 输出:I teach linux.、not 4900000448.

# 6. 匹配所有包含数字的行([]用法)
grep '[0-9]' re.txt
# 输出:包含QQ号、网址端口的行

# 7. 匹配以m或n开头的行([]+^用法)
grep '^[mn]' re.txt
# 输出:my开头和not开头的行

3.1.2 扩展正则实操(egrep/grep -E)

# 1. 匹配连续出现的0(+用法)
egrep '0+' re.txt
# 输出:my qq is 49000448、not 4900000448.

# 2. 匹配包含oldboy或linux的行(|用法)
egrep 'oldboy|linux' re.txt
# 输出:I am oldboy teacher!、I teach linux.、my blog is http://oldboy.blog.51cto.com等

# 3. 匹配tree、vim或sl软件是否安装(()用法)
rpm -qa | egrep '(tree|vim|sl)'
# 输出:已安装的tree、vim、sl相关软件包

# 4. 匹配3-5个连续的0({}用法)
egrep '0{3,5}' re.txt
# 输出:my qq is 49000448(包含3个0)

# 5. 匹配身份证号(18位,最后一位为数字或X)
cat > id.txt << EOF
230189199012251659
23018219590413055X
23018219610227185
EOF
egrep '[0-9]{17}[0-9X]$' id.txt
# 输出:前两条符合18位身份证规则的记录

3.1.3 Perl正则与括号表达式实操

# 1. Perl正则:快速匹配所有数字(\d用法)
grep -P '\d' re.txt
# 输出:包含数字的行(QQ号、网址)

# 2. 括号表达式:匹配字母数字字符([:alnum:]用法)
grep '[[:alnum:]]' re.txt
# 输出:包含字母或数字的所有行(等价于grep '[a-zA-Z0-9]' re.txt)

# 3. 括号表达式:匹配空白字符([:blank:]用法)
grep '[[:blank:]]' re.txt
# 输出:包含空格或制表符的行

3.2 Sed命令实战操作

3.2.1 Sed查找与打印(p动作)

# 环境准备:创建测试文件
cat > sed.txt << EOF
101,oldboy,CEO
102,bigbao,CTO
103,李导996,COO
104,yy,CFO
105,feixue,CIO
110,lidao,COCO
EOF

# 1. 打印第3行(行号定位)⭐️
sed -n '3p' sed.txt
# 输出:103,李导996,COO

# 2. 打印第2-5行(行号范围)⭐️
sed -n '2,5p' sed.txt
# 输出:第2到第5行内容

# 3. 打印包含oldboy的行(正则匹配)⭐️
sed -n '/oldboy/p' sed.txt
# 输出:101,oldboy,CEO

# 4. 打印从包含bigbao的行到包含lidao的行(范围匹配)
sed -n '/bigbao/,/lidao/p' sed.txt
# 输出:102,bigbao,CTO到110,lidao,COCO之间的所有行

# 5. 打印第3行和第5行(指定多行)
sed -n '3p;5p' sed.txt
# 输出:103,李导996,COO、105,feixue,CIO

# 6. 打印奇数行(规律查找)
seq 10 | sed -n '1~2p'
# 输出:1、3、5、7、9

# 7. 过滤日志时间范围(实战场景)
# 提取access.log中11:05到11:06的日志
sed -n '/2015:11:05:00/,/2015:11:06:00/p' access.log | wc -l
# 输出:符合时间范围的日志条数

3.2.2 Sed替换操作(s动作)

# 1. 将lidao替换为oldboy(全局替换)⭐️
sed 's#lidao#oldboy#g' sed.txt
# 说明:s=替换,#=分隔符(可替换为/或@),g=全局替换
# 输出:110,oldboy,COCO(lidao已替换为oldboy)

# 2. 直接修改原文件并备份(推荐生产环境)⭐️
sed -i.bak 's#bigbao#oldbao#g' sed.txt
# 说明:-i.bak会生成sed.txt.bak备份文件,修改原文件
cat sed.txt
# 输出:102,oldbao,CTO(bigbao已替换为oldbao)

# 3. 替换配置文件中的注释行(结合正则)
# 排除/etc/ssh/sshd_config中的空行和注释行,替换Port为2222
sed -i 's#^Port 22#Port 2222#g' /etc/ssh/sshd_config
grep -v '^$' /etc/ssh/sshd_config | grep -v '^#' | grep Port
# 输出:Port 2222

3.2.3 Sed后向引用(进阶提取)⭐️

# 环境准备:复制passwd文件用于测试
cp /etc/passwd ./test_passwd

# 1. 案例1:调换test_passwd第1列(用户名)和最后1列(Shell)的顺序
sed -r 's#^(.*)(:x.*:)(.*$)#\3\2\1#g' test_passwd
# 说明:
# ^(.*):第1组,匹配用户名(行开头到第一个:前的内容)
# (:x.*:):第2组,匹配中间部分(从:x到最后一个:的内容)
# (.*$):第3组,匹配Shell路径(最后一个:到行尾)
# \3\2\1:引用分组内容,调换第1组和第3组顺序
# 输出:/bin/bash:x:0:0:root:/root:root(用户名和Shell已调换)

# 2. 案例2:提取eth0网卡的IP地址
ip a s eth0 | sed -nr '3s#^.*et ([0-9.]+)/.*$#\1#gp'
# 说明:
# -n:取消默认输出,-r:支持扩展正则
# 3:定位第3行(IP所在行)
# ^.*et ([0-9.]+)/.*$:匹配IP地址(数字+点号组合)并分组
# \1:引用分组的IP地址,p:打印结果
# 输出:10.0.0.200(网卡eth0的IP地址)

# 3. 案例3:提取文件权限(如stat /etc/hosts中的0644)
stat /etc/hosts | sed -nr '4s#^.*\(([0-9]+)/.*$#\1#gp'
# 输出:0644(/etc/hosts的文件权限)

3.2.4 Sed删除与新增操作(d/a/i/c动作)

# 1. 删除操作(d动作)
# 1.1 删除sed.txt第4行
sed -i '4d' sed.txt
cat sed.txt
# 输出:第4行(104,yy,CFO)已删除

# 1.2 删除包含feixue的行
sed -i '/feixue/d' sed.txt
cat sed.txt
# 输出:包含feixue的行已删除

# 1.3 删除空行和以#开头的注释行(配置文件清理)⭐️
sed -r '/^$|^#/d' /etc/ssh/sshd_config > sshd_config.clean
# 输出:生成无空行、无注释的干净配置文件

# 2. 新增操作(a/i动作)
# 2.1 在第3行后新增内容(a动作)
sed '3a 999,lidao007,UFO' sed.txt
# 输出:第3行后新增999,lidao007,UFO

# 2.2 在第3行前插入内容(i动作)
sed '3i 999,lidao007,UFO' sed.txt
# 输出:第3行前插入999,lidao007,UFO

# 3. 替换整行内容(c动作)
sed '3c 999,lidao007,UFO' sed.txt
# 输出:第3行内容替换为999,lidao007,UFO

3.3 Awk命令实战操作

3.3.1 Awk取行操作(NR变量)⭐️

# 1. 取第1行
awk 'NR==1 {print $0}' /etc/passwd
# 输出:/etc/passwd第1行(root:x:0:0:root:/root:/bin/bash)

# 2. 取第2-5行
awk 'NR>=2 && NR<=5 {print $0}' /etc/passwd
# 输出:/etc/passwd第2到第5行内容

# 3. 取包含root或nobody的行(正则匹配)
awk '/root|nobody/ {print $0}' /etc/passwd
# 输出:包含root或nobody的所有行

# 4. 取从包含root的行到包含nobody的行(范围匹配)
awk '/root/,/nobody/ {print $0}' /etc/passwd
# 输出:从root行到nobody行之间的所有行

3.3.2 Awk取列操作($n/NF变量)⭐️

# 1. 取ls -lh结果的大小列(第5列)和文件路径列(最后一列)
ls -lh /etc/ | awk '{print $5,$NF}' | column -t
# 说明:$5=第5列(大小),$NF=最后一列(文件路径),column -t对齐输出
# 输出:对齐后的文件大小和路径列表

# 2. 取/etc/passwd的第1列(用户名)、第3列(UID)、最后一列(Shell)
awk -F':' '{print $1,$3,$NF}' /etc/passwd | column -t
# 说明:-F':'指定分隔符为冒号,适配/etc/passwd格式
# 输出:对齐后的用户名、UID、Shell路径

# 3. 提取eth0网卡IP地址(复杂分隔符)
# 方法1:指定分隔符为空格或/(连续符号合并)
ip a s eth0 | awk -F'[ /]+' 'NR==3 {print $3}'
# 说明:NR==3定位IP所在行,-F'[ /]+'表示以空格或/为分隔符(连续符号算一个)
# 输出:10.0.0.200

# 方法2:双分隔符截取
ip a s eth0 | awk -F 'inet |/24' 'NR==3 {print $2}'
# 说明:以"inet "或"/24"为分隔符,直接截取IP部分
# 输出:10.0.0.200

3.3.3 Awk取行+取列(多条件筛选)⭐️

# 1. 取/etc/passwd中UID(第3列)大于1000的行,输出用户名和UID
awk -F':' '$3>1000 {print $1,$3}' /etc/passwd | column -t
# 说明:$3>1000为条件(UID大于1000),动作是打印第1列和第3列
# 输出:普通用户的用户名和对应的UID

# 2. 筛选第4列(GID)以0或1开头的行,输出用户名、UID、GID
awk -F':' '$4 ~ /^[01]/ {print $1,$3,$4}' /etc/passwd | column -t
# 说明:$4 ~ /^[01]/表示第4列以0或1开头,~为包含匹配符
# 输出:GID以0或1开头的用户信息

# 3. 监控swap使用(超过0则报警)
free | awk '/Swap:/ {if($3>0) print "异常:系统开始占用swap,系统异常,请排查"}'
# 说明:/Swap:/匹配Swap行,if($3>0)判断已使用swap大于0,执行打印报警信息
# 输出:若swap占用>0,显示报警信息

3.3.4 Awk统计与计算⭐️

# 1. 统计/etc/passwd的总行数(计数)
awk '{i=i+1} END{print "总行数:"i}' /etc/passwd
# 说明:i=i+1累加计数,END{}在处理完所有行后执行
# 输出:总行数:XX(实际行数)

# 2. 计算1-10的总和
seq 10 | awk '{sum=sum+$1} END{print "总和:"sum}'
# 说明:sum=sum+$1累加每行第1列,END{}输出结果
# 输出:总和:55

# 3. 统计日志中密码错误的IP出现次数(基础统计)
grep 'failed' /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c
# 说明:先提取错误IP(倒数第4列),再排序去重统计次数
# 输出:IP出现次数和对应IP

3.4 特殊符号实战操作

3.4.1 引号系列实操

# 1. 单引号(所见即所得)
echo '当前用户: $(whoami), UID: $UID, 序列: {1..5}'
# 输出:当前用户: $(whoami), UID: $UID, 序列: {1..5}

# 2. 双引号(解析变量和命令)
echo "当前用户: $(whoami), UID: $UID, 序列: {1..5}"
# 输出:当前用户: root, UID: 0, 序列: {1..5}({1..5}不解析)

# 3. 不加引号(解析变量、命令和通配符)
echo 当前用户: $(whoami), UID: $UID, 序列: {1..5}
# 输出:当前用户: root, UID: 0, 序列: 1 2 3 4 5

# 4. 反引号(命令替换)
echo "当前目录: `pwd`, 系统时间: `date +%Y-%m-%d`"
# 输出:当前目录: /root, 系统时间: 2024-05-20

3.4.2 重定向符号实操⭐️

# 1. 标准输出重定向(覆盖写入)
echo "Hello Linux" > test.txt
cat test.txt
# 输出:Hello Linux

# 2. 标准输出追加重定向(追加写入)
echo "Hello Oldboy" >> test.txt
cat test.txt
# 输出:Hello Linux、Hello Oldboy

# 3. 错误输出重定向(捕获错误)
eco "Test Error" 2> error.txt  # eco为错误命令
cat error.txt
# 输出:-bash: eco: command not found

# 4. 合并输出(标准+错误)
echo "正常内容" &>> all.log
eco "错误内容" &>> all.log
cat all.log
# 输出:正常内容、-bash: eco: command not found

# 5. 多行写入文件(here-document)⭐️
cat > oldboy.txt << EOF
I love Linux
I like oldboyedu
Today is a good day
EOF
cat oldboy.txt
# 输出:3行写入内容

# 6. 输入重定向(搭配xargs)
echo -e "1 2 3\n4 5 6\n7 8 9" > num.txt
xargs -n3 < num.txt  # 按3个一组输出
# 输出:1 2 3、4 5 6、7 8 9

3.4.3 通配符实操⭐️

# 1. *匹配任意文件
ls *.txt
# 输出:当前目录下所有.txt后缀文件

# 2. ?匹配单个字符
ls /bin/??
# 输出:/bin目录下2个字符的命令(如ls、cp、mv)

# 3. {}生成序列/枚举
# 生成数字序列
echo {1..10}  # 输出:1 2 ... 10
echo {01..10} # 输出:01 02 ... 10(等宽数字)

# 生成字符序列
echo {a..z..2} # 输出:a c e ... y(步长2)

# 批量创建文件
touch oldboy{1..5}.log
# 生成:oldboy1.log到oldboy5.log

# 批量备份文件
cp oldboy.txt{,.bak}
# 等价于:cp oldboy.txt oldboy.txt.bak

# 4. []限定字符范围
ls oldboy[135].log
# 输出:oldboy1.log、oldboy3.log、oldboy5.log

# 5. [^]反向匹配
ls oldboy[^0-9].log
# 输出:非数字结尾的oldboy*.log文件

3.5 磁盘故障排查实操(No space left on device)

# 1. 故障复现:模拟磁盘空间满
dd if=/dev/zero of=/test.img bs=1G count=10  # 生成10G大文件,填满磁盘
touch /test.txt  # 提示:No space left on device

# 2. 排查步骤
# 2.1 检查磁盘空间
df -h
# 输出:/分区使用率100%

# 2.2 检查inode节点(排除inode耗尽)
df -i
# 输出:inode使用率正常

# 2.3 查找大文件(逐层排查)
du -sh //* | sort -rh | head -10  # 查找根目录下最大的10个文件
# 输出:/test.img占用10G

# 2.4 检查已删除但未释放的文件
lsof | grep delete
# 输出:无此类文件(若有,需重启对应进程释放)

# 3. 解决方案
rm -rf /test.img  # 删除大文件
touch /test.txt  # 可正常创建,故障解决

四、原理说明

4.1 正则表达式匹配原理

  • 贪婪匹配:正则默认“尽可能多匹配”,如.*o会匹配从开头到最后一个o的所有内容(而非第一个o);
  • 匹配顺序:从左到右逐字符匹配,遇到符合条件的内容即记录,直到行尾;
  • 符号优先级:分组() > 重复*+?{} > 连接(如oldboy) > 或|
  • 中括号特性[]内的特殊符号(如*.)会自动失去特殊含义,无需转义(如[.*]匹配实际的.或*);
  • 括号表达式原理:遵循POSIX标准,跨locale环境兼容,避免因字符编码差异导致匹配失败(如[:alnum:]在不同系统中均匹配字母数字)。

4.2 三剑客工作原理

4.2.1 Sed命令工作原理

  1. 读取行:Sed从输入文件/流中逐行读取内容,存入缓冲区(模式空间);
  2. 处理行:根据指定的“条件+动作”处理缓冲区中的行(如匹配正则后打印、替换、提取);
  3. 输出行:处理完成后,将缓冲区中的行输出到屏幕(-n选项会关闭默认输出,仅输出匹配行);
  4. 循环执行:重复上述步骤,直到所有行处理完毕;
  5. 修改文件:默认不修改原文件,-i选项会将缓冲区的修改写入原文件,-i.bak会先备份再修改。

4.2.2 Awk命令工作原理

  1. 初始化:读取命令行选项和模式动作,准备处理;
  2. 读取行:逐行读取输入文件/流,自动按指定分隔符分割字段(默认空白字符);
  3. 设置变量:为每行设置NR(行号)、NF(字段数)、$0(整行)、$n(第n列)等变量;
  4. 条件判断:判断当前行是否满足“条件”,满足则执行对应的“动作”;
  5. 循环执行:重复步骤2-4,直到所有行处理完毕;
  6. 收尾执行:若有END{}块,执行收尾操作(如输出统计结果)。

4.3 特殊符号工作原理

4.3.1 引号解析原理

  • Shell执行命令时,会先解析引号内的内容:单引号完全不解析,双引号解析变量和命令替换,不加引号额外解析通配符;
  • 反引号与$(...)等价,属于命令替换,Shell会先执行内部命令,将结果替换回命令行再执行整体命令。

4.3.2 重定向原理

  • Linux中每个进程默认打开3个文件描述符:0(标准输入)、1(标准输出)、2(标准错误输出);
  • 重定向符号通过修改文件描述符的指向,改变输入/输出的来源/目标(如> file将1指向file,2>&1将2指向1的目标)。

4.3.3 通配符匹配原理

  • 通配符由Shell解析(而非命令本身),Shell先扩展通配符为匹配的文件名列表,再将列表作为参数传递给命令;
  • 通配符匹配优先级:*/? > []/[^] > {},仅匹配文件名,不匹配文件内容(与正则区分)。

4.4 磁盘故障原理

  • 磁盘空间满:物理存储空间耗尽,无法写入新数据,需删除无用文件释放空间;
  • inode耗尽:每个文件/目录占用一个inode节点,若大量小文件导致inode用尽,即使有磁盘空间也无法创建文件;
  • 文件已删除但进程未释放:文件被删除但仍被进程占用,磁盘空间未实际释放,需重启进程或发送信号让进程释放。

五、注意事项

  1. 正则符号注意

    • 所有正则符号均为英文符号,避免使用中文符号(如中文的代替.);
    • 转义字符\仅在基础正则中需要(如\(),扩展正则(sed -r/egrep/awk)中无需转义+|(){}?
    • 正则与通配符区分:正则用于匹配文件内容,通配符用于匹配文件名,避免混淆(如*在正则中表示重复,在通配符中表示任意字符)。
  2. 三剑客选型注意

    • 单纯过滤内容(如日志筛选):优先选grep/egrep(速度最快);
    • 行级修改(如配置文件替换、删除行):优先选Sed;
    • 字段提取、统计计算、多条件筛选:优先选Awk;
    • 复杂场景可组合使用(如grep 筛选 | awk 取列 | sort 排序)。
  3. 特殊符号注意

    • 重定向>会覆盖文件内容,使用前需确认文件是否有用,避免误删数据;
    • here-document的结束标记(如EOF)需单独一行,前后不能有多余空格或字符;
    • 通配符*在空目录下会原样输出(如ls *.txt输出*.txt),可结合shopt -s nullglob优化(空匹配时不输出)。
  4. 磁盘故障排查注意

    • 执行rm -rf删除大文件时,需确认文件路径正确,避免误删系统核心文件;
    • 排查inode耗尽时,需查找大量小文件(如/tmp目录下的临时文件),删除后释放inode;
    • 生产环境建议定期清理日志、临时文件,避免磁盘空间满导致服务故障。

六、总结与避坑指南

6.1 总结

本文整合四份PDF全量内容,构建了Linux文本处理与系统运维的完整技术体系,核心覆盖四大模块:

  1. 正则表达式:文本匹配的基础,提供精准的内容定位能力,适配不同场景的匹配需求;
  2. 三剑客工具:grep(过滤)、Sed(修改)、Awk(分析),解决文本处理的核心需求;
  3. 特殊符号:引号(字符串处理)、重定向(IO控制)、通配符(文件匹配),提升命令行与脚本效率;
  4. 故障排查:磁盘空间不足故障的复现、排查与解决,覆盖运维常见场景。

核心原则:文本处理的核心是“精准匹配+高效处理”,特殊符号是“效率提升工具”,故障排查是“运维必备技能”,三者结合可解决Linux系统中绝大多数文本与基础运维问题,是运维新手入门与资深运维提升的核心知识点。

6.2 避坑指南

坑点 解决方案
正则与通配符混淆(如用*匹配文件内容) 明确场景:匹配文件内容用正则,匹配文件名用通配符
Sed替换时包含/导致语法错误 切换分隔符,如sed 's#http://#https://#g' file
重定向>误覆盖重要文件 优先使用>>追加,或备份文件(cp file file.bak
Awk取列时分隔符错误导致列错位 -F指定正确分隔符,复杂场景用正则(如-F'[ /]+'
通配符在空目录下原样输出 开启shopt -s nullglob,空匹配时不输出通配符本身
磁盘故障排查时误删核心文件 删除文件前用ls验证路径,生产环境开启文件备份
双引号中{}不解析 不加引号或用eval(如eval echo "序列: {1..5}"
行尾空格导致正则匹配失败(如^root $ ^root[[:space:]]*$匹配含空格的行尾
Sed后向引用无法生效 忘记加-r选项,需执行sed -r 's#(分组)#\1#g' file
inode耗尽导致无法创建文件 df -i排查,删除大量小文件(如rm -rf /tmp/*
posted @ 2026-03-11 23:02  gzjwo  阅读(4)  评论(0)    收藏  举报