文本处理三剑客
最后更新: 2026-01-07
作者: Linux Team
页面目录
目录
文本处理工具概述
Linux的文本处理三剑客(grep、sed、awk)是系统管理中最强大的工具。掌握它们可以高效完成日志分析、文本处理、数据提取等任务。
┌─────────────────────────────────────────────────────────────┐
│ 文本处理三剑客 │
├─────────────────────────────────────────────────────────────┤
│ │
│ grep ─── 文本搜索,模式匹配 │
│ ├── 功能: 查找字符串 │
│ ├── 擅长: 正则表达式匹配、文本过滤 │
│ └── 家族: grep, egrep, fgrep, zgrep │
│ │
│ sed ─── 流编辑器,增删改查 │
│ ├── 功能: 文本替换、修改、删除 │
│ ├── 擅长: 批量替换、按行处理 │
│ └── 特点: 非交互式编辑,自动处理 │
│ │
│ awk ─── 报告生成器,数据提取 │
│ ├── 功能: 模式扫描、字段处理 │
│ ├── 擅长: 格式化输出、报表生成 │
│ └── 特点: 完整的编程语言 │
│ │
└─────────────────────────────────────────────────────────────┘
grep 高级用法
正则表达式基础
# 字符类
[abc] 匹配 a、b 或 c
[^abc] 匹配除了 a、b、c 之外的字符
[a-z] 匹配小写字母
[A-Z] 匹配大写字母
[0-9] 匹配数字
# 预定义字符类
[:alpha:] 字母
[:digit:] 数字
[:alnum:] 字母和数字
[:space:] 空白字符
[:upper:] 大写字母
[:lower:] 小写字母
# 量词
* 零个或多个
+ 一个或多个
? 零个或一个
{n} 恰好n个
{n,} n个或更多
{n,m} n到m个
# 位置锚点
^ 行首
$ 行尾
\< 词首
\> 词尾
\b 词边界
# 特殊字符
. 任意单个字符
| 或
() 分组
\ 转义
grep选项详解
# 基本选项
-i, --ignore-case # 忽略大小写
-v, --invert-match # 反向匹配
-n, --line-number # 显示行号
-c, --count # 计数匹配行
-l, --files-with-matches # 只显示文件名
-L, --files-without-match # 显示不匹配的文件名
-h, --no-filename # 不显示文件名
-H, --with-filename # 显示文件名(默认)
-o, --only-matching # 只显示匹配部分
-b, --byte-offset # 显示字节偏移
-A, --after-context=N # 显示匹配后N行
-B, --before-context=N # 显示匹配前N行
-C, --context=N # 显示前后N行
# 正则选项
-E, --extended-regexp # 扩展正则
-G, --basic-regexp # 基本正则(默认)
-P, --perl-regexp # Perl正则
-F, --fixed-strings # 固定字符串(非正则)
-f, --file=FILE # 从文件读取模式
# 其他选项
-e, --regexp=PATTERN # 指定多个模式
-w, --word-regexp # 整词匹配
-x, --line-regexp # 整行匹配
-q, --quiet, --silent # 静默模式
--color=auto # 颜色高亮
-r, -R, --recursive # 递归搜索
grep实战案例
# 1. 日志分析
# 查找错误日志
grep -i "error" /var/log/syslog
grep -E "error|warning|critical" /var/log/syslog
# 排除某些行
grep "error" /var/log/syslog | grep -v "debug"
# 统计错误数量
grep -c "error" /var/log/syslog
# 2. 配置文件分析
# 查找注释和空行
grep -v '^#' /etc/nginx/nginx.conf | grep -v '^$'
# 查找生效的配置
grep -E '^[^#]*' /etc/nginx/nginx.conf
# 3. IP地址提取
grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' access.log
# 4. 进程分析
ps aux | grep nginx | grep -v grep
ps -ef | grep "[n]ginx"
# 5. 用户分析
grep -E "^root:|^admin:" /etc/passwd
grep -E "bash$|sh$" /etc/passwd
# 6. URL提取
grep -oE 'https?://[^[:space:]]+' access.log
# 7. 邮件地址提取
grep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' emails.txt
# 8. 日期时间匹配
grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2}' logs.txt
grep -E '[0-9]{2}:[0-9]{2}:[0-9]{2}' logs.txt
grep与管道配合
# 监控日志
tail -f /var/log/syslog | grep --line-buffered "error"
# 分析命令输出
df -h | grep -E "^/dev"
# 组合多个条件
ps aux | grep python | grep -v grep | awk '{print $2}'
# 去重计数
cat access.log | grep "200" | awk '{print $7}' | sort | uniq -c | sort -rn
grep家族
# grep - 基本正则
grep "pattern" file
# egrep / grep -E - 扩展正则
egrep "pattern1|pattern2" file
grep -E "one|two|three" file
# fgrep / grep -F - 固定字符串(更快)
fgrep "exact.string" file
grep -F "exact.string" file
# zgrep - 压缩文件搜索
zgrep "pattern" file.gz
# agrep - 近似匹配
agrep "patter" file
sed 高级用法
sed工作原理
┌─────────────────────────────────────────────────────────────┐
│ sed 工作流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 输入文件 ──→ 读取一行 ──→ 执行命令 ──→ 输出行 ──→ 下一行 │
│ │
│ 默认行为: 输入行会原样输出到屏幕,处理的行会变化 │
│ -n 禁用自动输出,配合p显示 │
│ │
└─────────────────────────────────────────────────────────────┘
sed命令详解
# 替换命令 s
s/old/new/ # 替换第一个匹配
s/old/new/g # 全局替换
s/old/new/2 # 每行第二个匹配
s/old/new/I # 忽略大小写
s/old/new/gi # 全局忽略大小写
# 分隔符选择(当替换内容含/时)
s|/old/path|/new/path|g
s#old#new#g
# 替换修饰符
s/old/new/p # 打印替换后的行
s/old/new/w file # 写入到文件
s/old/new/e # 执行命令(GNU sed)
# 其他命令
d # 删除
p # 打印
a\text # 追加文本
i\text # 插入文本
c\text # 替换整行
r file # 读取文件
w file # 写入文件
y/old/new/ # 字符转换
q # 退出
n/N # 下一行
} # 命令组结束
# 分支和测试
b label # 跳转到标签
t label # 测试替换成功则跳转
# hold和pattern空间
h/H # 复制/追加到hold
g/G # 复制/追加到pattern
x # 交换空间
sed地址模式
# 无地址 - 处理所有行
sed 's/old/new/' file
# 单地址 - 处理指定行
sed '5s/old/new/' file # 第5行
sed '5!s/old/new/' file # 除了第5行
# 地址范围
sed '1,10s/old/new/' file # 1-10行
sed '10,$s/old/new/' file # 10行到最后
# 正则匹配地址
sed '/pattern/s/old/new/' file # 匹配的行
sed '/pattern/!s/old/new/' file # 不匹配的行
# 步进
sed '~2s/old/new/' file # 从第2行开始,每隔1行
sed '1~2s/old/new/' file # 奇数行
# 组合
sed '1,/pattern/s/old/new/' file
sed '1,/pattern/{s/old/new/;s/old2/new2/}' file
sed实战案例
# 1. 文本替换
# 基本替换
sed 's/foo/bar/' file.txt
# 全局替换
sed 's/foo/bar/g' file.txt
# 多重替换
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt
# 2. 删除操作
# 删除空行
sed '/^$/d' file.txt
# 删除注释
sed '/^#/d' config.txt
sed '/^[[:space:]]*#/d' config.txt # 含空格的注释
# 删除特定行
sed '5d' file.txt # 删除第5行
sed '1,3d' file.txt # 删除1-3行
sed '/pattern/d' file.txt # 删除匹配行
# 3. 插入和追加
# 在第5行前插入
sed '5i\Inserted line' file.txt
# 在第5行后追加
sed '5a\Appended line' file.txt
# 在匹配行前插入
sed '/pattern/i\Before line' file.txt
# 在匹配行后追加
sed '/pattern/a\After line' file.txt
# 4. 替换整行
sed '/pattern/c\Replacement line' file.txt
# 5. 打印操作
sed -n '5p' file.txt # 只打印第5行
sed -n '1,10p' file.txt # 打印1-10行
sed -n '/pattern/p' file.txt # 只打印匹配行
sed -n '10q;p' file.txt # 打印前10行
# 6. 大小写转换(GNU sed)
sed 's/[a-z]/\U&/g' file.txt # 转大写
sed 's/[A-Z]/\L&/g' file.txt # 转小写
sed '1,10s/\b\(.\)/\U\1/g' file.txt # 首字母大写
# 7. 字段操作
sed 's/\t/,/g' file.txt # Tab转逗号
sed 's/ /_/g' file.txt # 空格转下划线
# 8. 备份并修改
sed -i.bak 's/old/new/g' file.txt
sed -i~ 's/old/new/g' file.txt # 备份为file.txt~
# 9. 读取和写入
sed '5r /etc/hosts' file.txt # 在第5行后插入hosts内容
sed '1w newfile.txt' file.txt # 写入第1行到新文件
sed -n 'w output.txt' file.txt # 写入所有到新文件
# 10. 多行处理
sed 'N;s/foo\nbar/baz/;P;D' file.txt # 合并两行处理
sed高级技巧
# 反向行
sed '1!G;h;$!d' file.txt
# 行号添加
sed = file.txt | sed 'N;s/\n/\t/'
# 提取奇偶行
sed 'n;d' file.txt # 奇数行
sed '1d;n;d' file.txt # 偶数行
# 交换行
sed -e '1!G;h;$!d' file.txt
# 单词首字母大写
sed 's/\b\(.\)/\u\1/g' file.txt
# 四则运算
echo "10+5" | sed 's/+/ + /' | bc
# 提取子串
echo "abc123def" | sed 's/.*\([0-9]\+\).*/\1/'
# 循环处理
sed ':a;N;$!ba;s/\n/ /g' file.txt # 所有行合并为一行
awk 高级用法
awk工作原理
┌─────────────────────────────────────────────────────────────┐
│ awk 工作流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ BEGIN { 初始化 } │
│ ↓ │
│ ┌─────────────────────────────────────────┐ │
│ │ 逐行读取文件 │ │
│ │ 分解为字段 $1, $2, ..., $NF │ │
│ │ 依次匹配模式 │ │
│ │ 执行匹配模式对应的动作 │ │
│ └─────────────────────────────────────────┘ │
│ ↓ │
│ END { 收尾处理 } │
│ │
└─────────────────────────────────────────────────────────────┘
awk内置变量
# 记录和字段变量
$0 当前整行
$1-$n 各字段
NF 当前行字段数
NR 当前记录号(行号)
FNR 当前文件记录号
ARGC 命令行参数数量
ARGV 命令行参数数组
# 文件和字段分隔符
FS 输入字段分隔符(默认空格)
OFS 输出字段分隔符(默认空格)
ORS 输出记录分隔符(默认换行)
RS 输入记录分隔符(默认换行)
RT 记录终止符
# 路径信息
FILENAME 当前输入文件名
SUBSEP 数组下标分隔符
# 数值格式化
OFMT 数字输出格式(默认%.6g)
CONVFMT 数字转换格式(默认%.6g)
awk格式化输出
# print语句
awk '{print $1, $2}' file.txt # 空格分隔
awk '{print $1 "\t" $2}' file.txt # Tab分隔
awk '{print $1, $2, $3}' file.txt # 逗号分隔
# printf语句(可格式化)
awk '{printf "%-10s %5d\n", $1, $2}' file.txt
# printf格式符
%s 字符串
%d 十进制整数
%f 浮点数
%x 十六进制
%o 八进制
%e 科学计数法
%5d 右对齐宽度5
%-5d 左对齐宽度5
%05d 补零宽度5
%6.2f 宽度6小数2位
awk模式和动作
# 空模式 - 匹配所有行
awk '{print $0}' file.txt
# 正则模式
awk '/pattern/' file.txt
awk '$3 ~ /regex/' file.txt # 字段匹配
awk '$3 !~ /regex/' file.txt # 字段不匹配
# 比较模式
awk '$3 > 100' file.txt
awk '$1 == "exact"' file.txt
awk '$2 != "value"' file.txt
# 逻辑模式
awk '$3 > 50 && $4 < 100' file.txt
awk '$2 == "A" || $2 == "B"' file.txt
awk 'NR == 5' file.txt
awk 'NR >= 5 && NR <= 10' file.txt
# 范围模式
awk '/start/,/end/' file.txt
awk 'NR==1,/pattern/' file.txt
# BEGIN/END
awk 'BEGIN {print "Start"} {print} END {print "End"}' file.txt
awk数组
# 基本数组
awk '{arr[$1]++} END {for (i in arr) print i, arr[i]}' file.txt
# 关联数组
awk '{
if (!($2 in seen)) {
seen[$2] = 1
print $2
}
}' file.txt
# 二维数组(模拟)
awk '{
arr[$1,$2] = $3
} END {
for (i in arr) {
split(i, tmp, SUBSEP)
print tmp[1], tmp[2], arr[i]
}
}' file.txt
# 删除数组元素
delete arr[$1]
delete arr
# 数组函数
length(arr) # 数组长度
sort(arr) # 排序(数值索引)
asort(arr) # 排序值
split(string, arr, sep) # 字符串分割
awk函数
# 字符串函数
length(str) # 字符串长度
split(str, arr, sep) # 分割字符串
substr(str, start, len) # 提取子串
index(str, substr) # 子串位置
match(str, regex) # 正则匹配
sub(regex, repl, str) # 替换第一个
gsub(regex, repl, str) # 全局替换
tolower(str) # 转小写
toupper(str) # 转大写
sprintf(fmt, ...) # 格式化
# 数学函数
sin(x), cos(x), sqrt(x)
int(x), rand(), srand(x)
exp(x), log(x), log10(x)
# 时间函数
systime() # Unix时间戳
strftime(fmt, time) # 格式化时间
# 用户自定义函数
awk 'function add(a, b) { return a + b }
{print add($1, $2)}' file.txt
awk实战案例
# 1. 日志分析
# 统计访问量
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -20
# 统计HTTP状态码
awk '{print $9}' access.log | sort | uniq -c
# 计算流量
awk '{sum+=$10} END {print sum/1024/1024 " MB"}' access.log
# 2. 数据统计
# 求和
awk '{sum+=$2} END {print sum}' data.txt
# 平均值
awk '{sum+=$2; count++} END {print sum/count}' data.txt
# 最大最小值
awk 'BEGIN {max=0} {if($2>max) max=$2} END {print max}' data.txt
# 3. 文本处理
# 列求和
awk -F',' '{sum+=$3} END {print sum}' data.csv
# 字段重新排版
awk -F: '{printf "%-15s %-10s %s\n", $1, $5, $7}' /etc/passwd
# 4. 条件统计
# 统计满足条件的行
awk '$3 > 100 {count++} END {print count}' data.txt
# 分组统计
awk '{count[$1]++} END {for (g in count) print g, count[g]}' data.txt
# 5. 数据验证
# 检查空行
awk 'NF==0 {count++} END {print "Empty lines:", count}' file.txt
# 检查重复
awk 'seen[$0]++ {print "Duplicate:", $0}' file.txt
# 6. 文件处理
# 合并文件
awk 'FNR==1 && NR!=1 {next} {print}' file1.txt file2.txt
# 跨行处理
awk 'BEGIN{RS=""} {print $1, $NF}' file.txt
# 7. 报表生成
awk 'BEGIN {
print "==========================="
print " Sales Report"
print "==========================="
printf "%-20s %10s %10s\n", "Product", "Qty", "Amount"
print "---------------------------"
}
{sum[$1]+=$2*$3}
END {
for (p in sum) {
printf "%-20s %10d %10.2f\n", p, count[p], sum[p]
}
}' sales.txt
三剑客组合使用
管道组合
# 日志分析综合
cat access.log | \
grep "2026-01-06" | \
awk '$9 == 200 {ips[$1]++} END {for (i in ips) print i, ips[i]}' | \
sort -k2 -rn | \
head -10
# 系统状态分析
ps aux | \
grep -v grep | \
awk '/nginx/ {cpu[$2]=$3; mem[$2]=$4} END {for(p in cpu) print p, cpu[p]"%", mem[p]"%"}'
# 文件内容处理
cat data.csv | \
grep -v "^#" | \
awk -F, '$3 > 100 {print $1","$2","$3}' | \
sort -t, -k3 -n
脚本实例
#!/bin/bash
# 日志分析脚本
LOG_FILE=${1:-/var/log/syslog}
OUTPUT_DIR="./report"
mkdir -p "$OUTPUT_DIR"
# 1. 统计错误级别
echo "=== Error Level Statistics ===" > "$OUTPUT_DIR/stats.txt"
grep -i "error\|critical\|alert\|emerg" "$LOG_FILE" | \
awk '{print $5}' | sort | uniq -c | sort -rn >> "$OUTPUT_DIR/stats.txt"
# 2. 统计IP访问量
echo -e "\n=== Top 20 IPs ===" >> "$OUTPUT_DIR/stats.txt"
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -20 >> "$OUTPUT_DIR/stats.txt"
# 3. 统计访问路径
echo -e "\n=== Top 20 Pages ===" >> "$OUTPUT_DIR/stats.txt"
awk '{print $7}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -20 >> "$OUTPUT_DIR/stats.txt"
echo "Report generated: $OUTPUT_DIR/stats.txt"
课后练习
实践任务
- 使用grep正则提取
/etc/passwd中的用户名和Shell - 用sed批量替换配置文件中的旧IP为新IP
- 用awk统计 Apache/Nginx 访问日志的各状态码数量
- 编写脚本分析系统日志,找出错误和警告
- 用三剑客组合从日志中提取并统计访问最多的URL
下一篇预告:我们将学习进程与服务管理,掌握Linux系统监控和控制技能。