5.4.2 流式编辑与过滤(sed)

流式编辑与过滤(sed)#

1. sed定位与常见场景#

sed(Stream Editor)适用于对文本流进行逐行处理、筛选与替换,常见于日志清洗、批量配置修改、数据格式化、管道链路过滤。其特点是非交互式、支持管道、可脚本化、可原地编辑。

原理草图(流式处理模型):

文章图片

2. 安装与版本检查#

大多数发行版默认自带 sed;容器与极简系统需显式安装。

安装:

# Debian/Ubuntu
sudo apt update && sudo apt install -y sed

# CentOS/RHEL/Alma/Rocky
sudo yum install -y sed

# Alpine
apk add --no-cache sed

版本确认:

sed --version
# 预期:输出 GNU sed 4.x 或 BusyBox sed 版本信息

3. 基本语法与执行模型#

  • 基本格式:sed [选项] '地址范围{命令}' 文件
  • 常用选项:
  • -n:默认不打印,配合p输出
  • -i:原地编辑(生产慎用)
  • -E:启用扩展正则
  • -f:读取脚本文件

命令解释示例(带预期):

# 准备示例文件
cat > /tmp/app.log <<'EOF'
INFO start
ERROR user=1001 action=login
WARN retry
ERROR user=1002 action=logout
EOF

# 仅打印包含 ERROR 的行
sed -n '/ERROR/p' /tmp/app.log
# 预期输出:
# ERROR user=1001 action=login
# ERROR user=1002 action=logout

# 只打印第2~3行
sed -n '2,3p' /tmp/app.log

4. 常用命令与示例(替换/删除/插入)#

替换:

# 每行仅替换第一个匹配
sed 's/ERROR/ERR/' /tmp/app.log

# 全行替换并屏蔽 user 数字
sed -E 's/(user)=([0-9]+)/\1=*** /g' /tmp/app.log

删除:

# 删除首行
sed '1d' /tmp/app.log

# 删除空行与注释行
cat > /tmp/app.conf <<'EOF'
# comment
PORT=8080

DEBUG=true
EOF
sed '/^#/d;/^$/d' /tmp/app.conf

插入与追加:

# 第1行前插入标题
sed '1i\title=APP' /tmp/app.conf

# 第3行后追加一行
sed '3a\TIMEOUT=30' /tmp/app.conf

5. 正则与转义要点#

  • 基本正则中+?需转义;-E启用扩展正则
  • 分隔符冲突可用其它符号:sed 's#/usr/local#/opt#g'
  • 行首行尾:^$
  • 反向引用:基本正则\(\)\1;扩展正则()

示例:替换路径分隔符

echo "/usr/local/bin" | sed 's#/usr/local#/opt#g'
# 预期:/opt/bin

6. 典型运维用法(含完整链路)#

批量修改配置并备份:

# 原地修改并生成 .bak 备份
sed -i.bak 's/^PORT=.*/PORT=8080/' /etc/myapp/app.conf
# 预期:/etc/myapp/app.conf 被修改,/etc/myapp/app.conf.bak 保留旧值

提取区间日志:

# 从时间段日志中提取
sed -n '/2024-01-01 00:00/,/2024-01-01 01:00/p' /var/log/app.log

清理空行并统一分隔符:

# 输入文件
cat > /tmp/data.txt <<'EOF'
a,b,c

1,2,3
EOF

# 删除空行并将全角逗号替换为半角
sed '/^$/d;s/,/,/g' /tmp/data.txt
# 预期:
# a,b,c
# 1,2,3

7. 与管道组合的惯用模式#

grep + sed 精准取样:

grep ERROR /tmp/app.log | sed -n '1,1p'
# 解释:先筛 ERROR,再取第一行

sed + awk 清洗字段:

# 将 | 转空格后取第1与第3字段
echo "u01|ok|200" | sed 's/|/ /g' | awk '{print $1,$3}'
# 预期:u01 200

8. 排错与最佳实践#

常见问题与排查:
1. -i 无效或报错:BusyBox sed 不支持 -i.bak 写法
解决:
bash # BusyBox 环境采用: sed -i 's/old/new/' file
2. 替换没生效:正则未匹配或行首行尾未考虑
排查:
bash sed -n '/pattern/p' file # 先验证匹配
3. 大量输出:忘记使用 -n
解决:
bash sed -n '1,5p' file

最佳实践:
- 原地修改前备份:sed -i.bak 's/old/new/g' file
- 复杂处理写脚本文件,便于版本管理:

cat > /tmp/rules.sed <<'EOF'
/^#/d
/^$/d
s/ERROR/ERR/g
EOF
sed -f /tmp/rules.sed /tmp/app.log

9. 练习(含答案提示)#

  1. 练习1:删除 /tmp/app.log 中所有 WARN 行并打印前2行
    参考命令:
    bash sed '/WARN/d' /tmp/app.log | sed -n '1,2p'
  2. 练习2:将 user=数字 替换为 user=***
    参考命令:
    bash sed -E 's/user=[0-9]+/user=***/g' /tmp/app.log
  3. 练习3:将配置文件中 DEBUG=false 改为 DEBUG=true 并备份
    参考命令:
    bash sed -i.bak 's/^DEBUG=false$/DEBUG=true/' /tmp/app.conf