文本处理三剑客

最后更新: 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"

课后练习

实践任务
  1. 使用grep正则提取 /etc/passwd 中的用户名和Shell
  2. 用sed批量替换配置文件中的旧IP为新IP
  3. 用awk统计 Apache/Nginx 访问日志的各状态码数量
  4. 编写脚本分析系统日志,找出错误和警告
  5. 用三剑客组合从日志中提取并统计访问最多的URL

下一篇预告:我们将学习进程与服务管理,掌握Linux系统监控和控制技能。