Appearance
11|sed 流编辑
grep 能找出匹配的行,但不能改内容。要把日志里的 IP 脱敏、把配置文件里的端口改掉、把空行删掉,这些"改文本"的活要靠 sed。
sed 是流编辑器(stream editor)——文本像流水一样经过,sed 按规则对每一行做处理。本篇讲 sed 最常用的替换、增删改,以及一个危险的坑:就地编辑。
一、最常用的替换
s/旧/新/ 是 sed 用得最多的命令——把"旧"替换成"新":
bash
echo "hello world" | sed 's/world/shell/'
# hello shell默认只替换每行第一个匹配。要全部替换加 g(global):
bash
echo "a b a b" | sed 's/a/X/'
# X b a b(只换第一个)
echo "a b a b" | sed 's/a/X/g'
# X b X b(全换)实战——日志脱敏,把 IP 换成 [IP]:
bash
sed -E 's/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[IP]/g' access.log-E 启用扩展正则(和 grep -E 一样),少写反斜杠。
二、定界符的选择
s/旧/新/ 用 / 做定界符。但如果模式里含 /(比如路径),要转义很乱:
bash
sed 's/\/var\/log/\/data\/log/' # 难读换定界符——sed 允许用任意字符,常用 # 或 |:
bash
sed 's#/var/log#/data/log#' # 清晰三、地址:只处理某些行
/旧/新/ 之前可以加地址,指定只处理哪些行:
bash
# 只处理第 3 行
sed '3s/error/ERROR/' file
# 处理 1 到 5 行
sed '1,5s/error/ERROR/' file
# 处理匹配某模式的行
sed '/nginx/s/error/ERROR/' file # 只在含 nginx 的行里替换
# 处理两个模式之间的行
sed '/start/,/end/s/error/ERROR/' file四、删除行
d 命令删除匹配的行:
bash
# 删空行
sed '/^$/d' file
# 删注释行
sed '/^#/d' file
# 删第 2 到 4 行
sed '2,4d' file清理配置文件——去掉注释和空行:
bash
sed -E '/^[[:space:]]*#/d; /^[[:space:]]*$/d' sshd_config; 分隔多条 sed 命令。
五、插入和追加
i(insert)在行前插入,a(append)在行后追加:
bash
# 在第 1 行前插入一行
sed '1i # 配置开始' file
# 在最后一行后追加
sed '$a # 配置结束' file六、就地编辑 -i
前面的命令都把结果输出到屏幕,不改原文件。要直接改原文件加 -i:
bash
sed -i 's/port 22/port 2222/' /etc/ssh/sshd_config-i 是危险操作——直接改原文件,没有撤销。生产环境一定要先备份:
bash
# GNU sed 支持自动备份
sed -i.bak 's/port 22/port 2222/' /etc/ssh/sshd_config
# 生成 sshd_config.bak 备份
# 或手动备份
cp file file.bak
sed -i 's/.../.../' filemacOS 的 sed 是 BSD 版,-i 后必须跟备份后缀(哪怕是空串 -i ''),和 GNU sed 行为不同。跨平台脚本要注意。
七、多行和复杂处理
sed 是按行处理的,跨行操作要用 N 把下一行读进来。这个比较绕,简单场景能避免就避免——复杂的跨行处理用 awk 更合适。
一个 sed 做不好的例子——把多行 JSON 格式化。这种结构化数据处理用 jq 或 Python 更靠谱,sed 强行处理易出错。
sed 的强项是按行做正则替换和增删,超出这个范围换工具。
八、实际例子
批量改一组配置文件的端口:
bash
for f in /etc/nginx/conf.d/*.conf; do
sed -i 's/listen 80;/listen 8080;/' "$f"
done提取 SQL 日志里的慢查询,去掉前缀时间戳:
bash
sed -E 's/^[0-9-]+ [0-9:]+ //' slow.log
# 2026-06-23 14:30:01 SELECT * FROM ... → SELECT * FROM ...九、sed 还是变量替换还是 awk
同样的事可能多种工具都能做,选哪个:
- 简单字符串替换、掐头去尾:用 Shell 变量
${}(上一篇讲过,不开子进程) - 按正则替换整行内容、删除特定行:用 sed
- 按字段处理、统计聚合:用 awk
bash
# 取文件名——用变量扩展最快
f="${path##*/}"
# 把日志里所有 IP 脱敏——用 sed
sed -E 's/[0-9.]+/[IP]/g' log
# 统计每个状态码出现次数——用 awk
awk '{count[$9]++} END {for (k in count) print k, count[k]}' access.log学会了之后
sed 是文本替换的主力。s/旧/新/g 全局替换、d 删行、i/a 插入、地址限定处理范围。-i 就地编辑方便但危险,生产先备份。复杂跨行处理交给 awk。
下一篇讲 awk——按字段处理文本的利器。