10-Linux 文本处理三剑客
在Linux中,正则表达式是文本处理的重要工具,结合 grep、sed 和 awk,可以高效地进行文本过滤、替换、统计等多种操作。
正则规则
| 正则表达式 | 描述 | 示例 | Basic RegEx | Extended RegEx | Python RegEx | Perl RegEx |
|---|---|---|---|---|---|---|
\ |
转义符,将特殊字符转义为其字面意义 | a\.b 匹配 “a.b”,不匹配 “ajb” |
支持 | 支持 | 支持 | 支持 |
^ |
匹配行首(或字符串开头,如在 awk 中) | ^tux 匹配以 “tux” 开头的行 |
支持 | 支持 | 支持 | 支持 |
$ |
匹配行尾(或字符串结尾,如在 awk 中) | tux$ 匹配以 “tux” 结尾的行 |
支持 | 支持 | 支持 | 支持 |
. |
匹配除换行符(\n)外的任意单个字符 |
ab. 匹配 “abc” 或 “abd”,不匹配 “abcd” |
支持 | 支持 | 支持 | 支持 |
[ ] |
匹配括号内包含的任意一个字符 | coo[kl] 匹配 “cook” 或 “cool” |
支持 | 支持 | 支持 | 支持 |
[^ ] |
匹配不在括号内的任意一个字符 | 123[45] 不匹配 “1234” 或 “1235”,匹配 “1236” |
支持 | 支持 | 支持 | 支持 |
[-] |
匹配指定字符范围内的任意一个字符 | [0-9] 匹配任意一个数字 |
支持 | 支持 | 支持 | 支持 |
? |
匹配前面的项 0 次或 1 次 | colou?r 匹配 “color” 或 “colour” |
不支持 | 支持 | 支持 | 支持 |
+ |
匹配前面的项 1 次或多次 | sa-6+ 匹配 “sa-6” 或 “sa-666” |
不支持 | 支持 | 支持 | 支持 |
* |
匹配前面的项 0 次或多次 | co*l 匹配 “cl”、”col”、”cool” |
支持 | 支持 | 支持 | 支持 |
( ) |
将表达式分组,创建一个子串或用于反向引用 | ma(tri)?x 匹配 “max” 或 “matrix” |
不支持 | 支持 | 支持 | 支持 |
{n} |
匹配前面的项恰好 n 次 | [0-9]{3} 匹配任意三位数 |
不支持 | 支持 | 支持 | 支持 |
{n,} |
匹配前面的项至少 n 次 | [0-9]{2,} 匹配任意两位数或更多位数 |
不支持 | 支持 | 支持 | 支持 |
{n,m} |
匹配前面的项至少 n 次,至多 m 次 | [0-9]{2,5} 匹配两位数到五位数 |
不支持 | 支持 | 支持 | 支持 |
| |
交替匹配,匹配 | 左边或右边的项 |
ab(c|d) 匹配 “abc” 或 “abd” |
不支持 | 支持 | 支持 | 支持 |
grep命令
- 基本语法
1
grep [选项] "模式" 文件名
常用示例
- 基础文本搜索
1
2
3
4
5# 在文件中查找包含特定字符串的行
grep "hello" file.txt
# 结合正则表达式匹配(需添加-E参数)
ip a | grep -E "ens33$" - 递归搜索
1
2
3
4
5
6
7
8# 递归查找/etc目录下包含'ens33'的文件
grep -r 'ens33' /etc
# 忽略大小写递归搜索
grep -ir 'ens33' /etc
# 忽略大小写并显示行号
grep -irn 'ens33' /etc - 正则表达式应用
1
2
3
4
5# 匹配以ens33结尾的行
grep -Er 'ens33$' /etc
# 排除空行和注释行(以#开头)
grep -Ev "^$|^#" file
sed命令
- 基本语法
1
sed [选项] '命令' 文件名
常用操作示例
- 文本替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 全局替换字符串
sed 's/old-string/new-string/g' input.txt > output.txt
# 替换文件中的Jack为Mark(仅每行第一个)
sed 's/Jack/Mark/' sed-examp.txt
# 全局替换Jack为Mark
sed 's/Jack/Mark/g' sed-examp.txt
# 替换第2-3行的hello为Hey
sed '2,3s/hello/Hey/g' sed-examp.txt
# 仅替换包含Pony的行
sed '/Pony/s/hello/Hi/g' sed-examp.txt
# 替换不包含Pony的行
sed '/Pony/!s/hello/Hi/g' sed-examp.txt - 删除操作
1
2
3
4
5
6
7
8# 删除第2-3行
sed '2,3d' sed-examp.txt
# 删除包含Pony的行
sed '/Pony/d' sed-examp.txt
# 删除空白行
sed '/^$/d' sed-examp.txt - 插入和追加
1
2
3
4
5
6
7
8# 在第一行前插入内容
sed '1i\Welcome' sed-examp.txt
# 在第一行后追加内容
sed '1a\Welcome' sed-examp.txt
# 在匹配行后追加内容
sed '/Pony/aWelcome' sed-examp.txt - 高级用法
1
2
3
4
5
6
7
8
9
10
11
12
13# 打印匹配行(类似grep)
sed -n '/Pony/p' sed-examp.txt
# 多条件操作
sed -e '/^$/d' -e '/Pony/d' sed-examp.txt
# 或
sed '/^$/d; /Pony/d' sed-examp.txt
# 直接修改源文件
sed -i -e '/^$/d' -e '/Pony/d' sed-examp.txt
# 修改源文件并备份
sed -i.bak '/^$/d; /Pony/d' sed-examp.txt - 高级文本处理
1
2
3
4
5
6
7
8
9
10# 交换两列内容
echo "Alice 30" | sed 's/\(.*\) \(.*\)/\2 \1/'
# 日志处理:提取ERROR信息并格式化
sed -n '/ERROR/s/\(202[0-9]-[0-9][0-9]-[0-9][0-9]\) .*ERROR\] \(.*\)/\1 \2/p' log.txt
# 简化写法
sed -n -r '/ERROR/s/(202[0-9]-[0-9][0-9]-[0-9]{2}) .*ERROR] (.*)/\1 \2/p' log.txt
# 日期格式转换
sed -n -r 's/([0-9]{4})-([0-9]{2})-([0-9]{2})(.*)/\3\/\2\/\1\4/p' log.txt
awk命令
- 基本语法
1
2
3
4
5# 格式1
awk [选项] '[条件]{指令}' 文件
# 格式2
前置指令 | awk [选项] '[条件]{指令}' - 内置变量
1
2
3
4
5
6
7$0:文本当前行的全部内容
$1、$2、$3...:文本的第1、2、3...列
NR:文件当前行的行号
NF:文件当前行的列数
常用示例
- 基础文本处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# 准备测试数据
head /etc/passwd > user
# 打印以bin开头的行
awk '/^bin/{print}' user
# 指定分隔符并打印特定列
awk -F: '/^bin/{print $6}' user
# 打印多列信息
awk -F: '/^bin/{print $6,NR,NF}' user
# 打印最后一列
awk -F: '/^bin/{print $6,NR,$NF}' user
# 打印以nologin结尾的用户名
awk -F: '/nologin$/{print $1}' user
# 多分隔符处理
awk -F[:/] '/nologin$/{print $1,$10}' user
# 格式化输出
awk -F: '{print "用户是: "$1" 使用的shell是: "$7}' user - 结构化输出
1
2# BEGIN、主体处理、END结合使用
awk -F: 'BEGIN{print "User\tUID\tHome"}{print $1"\t"$3"\t"$6}END{print "Total "NR" lines."}' /etc/passwd - 条件过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 正则表达式条件
awk -F: '$6~/root/{print}' user # 第六列包含root
awk -F: '$6!~/root/{print}' user # 第六列不包含root
# 数值比较
awk -F: '$3<3{print}' user # UID小于3
awk -F: '$3>=3{print}' user # UID大于等于3
awk -F: '$3!=3{print}' user # UID不等于3
# 多条件组合
awk -F: 'NR>3&&$3>5{print}' user # 行号>3且UID>5
awk -F: '$7~/bash/&&$3<500{print}' user # shell包含bash且UID<500
awk -F: '$7~/bash/||NR<=3' user # shell包含bash或行号<=3
awk -F: 'NR%2==0{print NR,$0}' user # 偶数行 - 数组应用
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# 统计单词出现次数
echo "apple orange banana apple orange" | awk '
{
for(i=1;i<=NF;i++) count[$i]++
}
END {
for(word in count) print word, count[word]
}'
# 统计IP访问次数(Web日志分析)
# 安装并启动Apache服务
yum install -y httpd
systemctl stop firewalld
setenforce 0
systemctl start httpd
# 生成访问日志
curl 127.0.0.1
curl 127.0.0.1
curl 127.0.0.1
# 统计IP访问次数
awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log
# 统计页面访问次数
awk -F\/ '{pages[$4]++}END{for(p in pages){print p,pages[p]}}' /var/log/httpd/access_log
总结
grep:专注于文本搜索和匹配
sed:擅长流编辑和文本转换
awk:具备完整的编程能力,适合复杂文本处理和数据提取
