✂️ 第22课:文本处理(awk/sed)

阶段四:Shell脚本第4/6课

📚 课程目标

一、grep进阶

grep -i "pattern" file       # 忽略大小写
grep -v "pattern" file       # 反向匹配
grep -c "pattern" file       # 匹配行数
grep -n "pattern" file       # 显示行号
grep -r "pattern" dir/       # 递归搜索
grep -l "pattern" *.txt      # 仅文件名
grep -w "word" file          # 全词匹配
grep -E "cat|dog" file       # 扩展正则
grep -A 3 "pat" file         # 匹配行+后3行
grep -B 2 "pat" file         # 匹配行+前2行

# 实用组合
grep -rn "TODO" --include="*.py" .
grep -v "^#" file | grep -v "^$"   # 非注释非空行

二、sed流编辑器

# 替换
sed 's/old/new/' file         # 每行第一个
sed 's/old/new/g' file        # 全部替换
sed -i 's/old/new/g' file     # 直接修改

# 删除
sed '/^#/d' file              # 删除注释行
sed '/^$/d' file              # 删除空行
sed '1,5d' file               # 删除1-5行

# 打印
sed -n '5,10p' file           # 打印5-10行

# 插入
sed '3i\inserted' file       # 第3行前插入

# 高级
sed 's/\w\+/[&]/g' file     # &为匹配内容,加[]
sed -i.bak 's/old/new/g' file # 备份后修改

三、awk文本处理

# 基本用法
awk '{print $1}' file              # 第1列
awk -F: '{print $1}' /etc/passwd   # 指定分隔符
awk '$3 > 100' file                # 过滤
awk '/pattern/' file               # 匹配

# 内置变量
# NR:行号  NF:字段数  FS:分隔符  OFS:输出分隔符

# 计算统计
awk '{sum += $1} END{print sum}' numbers
awk '{sum+=$1; c++} END{print sum/c}' numbers

# 格式化输出
awk '{printf "%-20s %10d\n", $1, $2}' file

# 条件处理
awk '$9 >= 400 {print $7, $9}' access.log

四、其他文本工具

# sort排序
sort -n file          # 数字排序
sort -rn file         # 倒序
sort -k2 -n file      # 按第2列排序
sort -t: -k3n /etc/passwd

# uniq去重(需先sort)
sort file | uniq -c   # 计数去重
sort file | uniq -d   # 仅重复行

# cut切列
cut -d: -f1 /etc/passwd
cut -c1-10 file

# tr替换
echo "HELLO" | tr 'A-Z' 'a-z'
tr -d '\r' < win.txt > unix.txt

# wc计数
wc -l file  # 行数
wc -w file  # 单词数

五、实战:日志分析

#!/bin/bash
# analyze-logs.sh
LOG="$1"

echo "===== 日志分析 ====="
echo "总行数: $(wc -l < "$LOG")"

echo "\n--- TOP 10 IP ---"
awk '{print $1}' "$LOG" | sort | uniq -c | sort -rn | head -10

echo "\n--- 状态码分布 ---"
awk '{print $9}' "$LOG" | sort | uniq -c | sort -rn

echo "\n--- TOP 10 URL ---"
awk '{print $7}' "$LOG" | sort | uniq -c | sort -rn | head -10

echo "\n--- 4xx/5xx错误 ---"
awk '$9 ~ /^[45]/ {print $9, $7}' "$LOG" | sort | uniq -c | sort -rn | head -10

六、练习

📝 文本处理实战

# 1. 提取用户名和UID
awk -F: '{print $1, $3}' /etc/passwd

# 2. 统计日志文件大小
du -sh /var/log/

# 3. 替换端口号
# sed 's/Port 22/Port 2222/' /etc/ssh/sshd_config

# 4. TOP 5大文件
find /var -type f -exec du -h {} + 2>/dev/null | sort -rh | head -5
🏆

成就解锁:文本处理大师

✅ 掌握grep高级搜索

✅ 掌握sed替换

✅ 掌握awk处理

✅ 学会组合工具

✅ 掌握日志分析

七、文本处理实战脚本

#!/bin/bash
# csv-process.sh - CSV文件处理

CSV_FILE="$1"
[[ -z "$CSV_FILE" ]] && echo "用法: $0 " && exit 1

# 表头
head -1 "$CSV_FILE"

# 过滤:第3列大于90
awk -F, '$3 > 90' "$CSV_FILE"

# 排序:按第3列降序
sort -t, -k3 -rn "$CSV_FILE"

# 统计:各分类计数
awk -F, '{count[$2]++} END {for (k in count) print k, count[k]}' "$CSV_FILE"

# 汇总:某列求和
awk -F, '{sum += $4} END {printf "总计: %.2f\n", sum}' "$CSV_FILE"

八、JSON处理

# 使用jq处理JSON
sudo apt install jq

# 解析JSON
echo '{"name":"Linux","ver":7}' | jq '.name'       # "Linux"
echo '[1,2,3]' | jq '.[0]'                           # 1
echo '{"a":1,"b":2}' | jq 'keys'                     # ["a","b"]

# API响应处理
curl -s https://api.github.com/repos/torvalds/linux | \
    jq '{name: .name, stars: .stargazers_count}'

# 过滤数组
echo '[{"n":"a","v":1},{"n":"b","v":2}]' | jq '.[] | select(.v > 1)'

九、多文件处理

# 批量替换文件内容
for f in *.conf; do
    sed -i.bak 's/old_host/new_host/g' "$f"
done

# 合并CSV文件(去重表头)
head -1 file1.csv > merged.csv
tail -n +2 -q file*.csv >> merged.csv

# 按日期分割日志
awk '/2024-01-15/ {print > "log-15.log"}
     /2024-01-16/ {print > "log-16.log"}' access.log

附录:文本处理学习资源

推荐书籍

书名作者重点
Linux命令行与Shell脚本编程大全BlumShell脚本全面覆盖
UNIX/Linux系统管理技术手册Nemeth系统管理圣经
Ansible: Up and RunningLintnerAnsible实战
鸟哥的Linux私房菜鸟哥中文经典入门

在线资源

认证路径

认证机构级别
LFCSLinux Foundation基础系统管理
LFCELinux Foundation高级系统工程师
RHCSARed HatRed Hat管理员
RHCERed HatRed Hat工程师
CKA/CKADCNCFKubernetes管理员/开发者

实践环境

常用速查表

# 文本处理速查
grep -E 'pattern' file     # 扩展正则搜索
sed -i 's/old/new/g' file  # 替换
awk '{print $1}' file     # 提取列
sort | uniq -c | sort -rn   # 频次统计
cut -d: -f1 file            # 切列
tr 'A-Z' 'a-z'             # 转小写

# 系统管理速查
systemctl status/start/stop/restart service
journalctl -u service -f    # 跟踪日志
df -h / du -sh *            # 磁盘使用
ps aux --sort=-%mem         # 内存排序
ss -tlnp                    # 监听端口
iptables -L -n              # 防火墙规则
crontab -e                  # 编辑定时任务
useradd -m -s /bin/bash user # 创建用户

# 网络诊断速查
ip addr / ip route          # 网络配置
ping / traceroute           # 连通测试
dig / nslookup              # DNS查询
curl -I url                 # HTTP头检查
nc -zv host port            # 端口测试
tcpdump -i eth0 port 80     # 抓包

十、实机验证记录

$ grep --version | head -1
grep (GNU grep) 3.11
$ sed --version | head -1
sed (GNU sed) 4.9
$ awk --version | head -1 2>/dev/null || mawk -W version 2>/dev/null | head -1
GNU Awk 5.2.1, API 3.2, PMA Avon 8-g1, (GNU MPFR 4.2.1, GNU MP 6.3.0)
$ echo "hello world" | awk '{print $1}'
hello

十一、生产环境文本处理脚本

#!/bin/bash
# log-rotate.sh - 日志轮转脚本
LOG_DIR="/var/log/app"
MAX_SIZE="100M"
KEEP_DAYS=30

# 检查并轮转大日志
find "$LOG_DIR" -name "*.log" -size +"$MAX_SIZE" | while read log; do
    ts=$(date +%Y%m%d_%H%M%S)
    mv "$log" "${log}.$ts"
    gzip "${log}.$ts"
    touch "$log"
    echo "轮转: $log -> ${log}.$ts.gz"
done

# 清理旧日志
find "$LOG_DIR" -name "*.gz" -mtime +"$KEEP_DAYS" -delete
echo "清理${KEEP_DAYS}天前的压缩日志"

# 敏感信息脱敏
scrub_sensitive() {
    sed -E         -e "s/[0-9]{1,3}(\.[0-9]{1,3}){3}/[IP_REDACTED]/g"         -e "s/(password|passwd|pwd)[[:space:]]*[:=][[:space:]]*.*/\1=[REDACTED]/gi"         -e "s/[0-9]{16,19}/[CARD_REDACTED]/g"
}

十一、生产环境文本处理

#!/bin/bash
# log-rotate.sh
LOG_DIR="/var/log/app"; MAX_SIZE="100M"; KEEP=30
find "$LOG_DIR" -name "*.log" -size +"$MAX_SIZE" | while read log; do
    ts=$(date +%Y%m%d_%H%M%S)
    mv "$log" "${log}.$ts"; gzip "${log}.$ts"; touch "$log"
done
find "$LOG_DIR" -name "*.gz" -mtime +"$KEEP" -delete

# 脱敏处理
scrub() {
    sed -E 's/[0-9]{1,3}(\.[0-9]{1,3}){3}/[IP]/g' \
         -e 's/(password|pwd)[[:space:]]*[:=].*/\1=[RED]/gi'
}

专题:文本处理流水线设计

在实际生产环境中,文本处理流水线设计是系统管理员必须深入掌握的核心能力。本节将探讨常见场景、最佳实践和避坑指南。

常见问题与解决方案

问题1:脚本在生产环境运行异常

开发环境和生产环境的差异是脚本出错的常见原因。建议:

问题2:性能不达预期

优化策略:

问题3:可维护性差

改善方法:

最佳实践总结

#!/bin/bash
# 文本处理流水线设计最佳实践模板
set -euo pipefail

# 1. 参数校验
[[ $# -lt 1 ]] && echo "Usage: $0 <arg>" >&2 && exit 1

# 2. 环境检查
require_cmd() {
    command -v "$1" >/dev/null || { echo "需要: $1" >&2; exit 1; }
}

# 3. 清理机制
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

# 4. 日志记录
log() { echo "[$(date +%T)] $*"; }
err() { log "ERROR: $*" >&2; exit 1; }

# 5. 主逻辑
main() {
    log "开始处理: $1"
    # 业务逻辑
    log "处理完成"
}

main "$@"

进阶方向