Skip to content

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/.../.../' file

macOS 的 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——按字段处理文本的利器。