sed 默认不修改原文件,仅输出结果到标准输出;加 -i 参数可就地编辑,但 macos 要求 -i 后跟空字符串或备份后缀,linux 则无需。

sed 替换文件内容时为什么原文件没变
因为 sed 默认不修改原文件,只是把处理结果输出到标准输出。你看到终端里打印出新内容,但 file.txt 本身纹丝不动。
- 加
-i参数才能就地编辑:sed -i 's/old/new/g' file.txt - macOS 的
sed要求-i后必须跟后缀(哪怕为空):sed -i '' 's/old/new/g' file.txt - 想先预览效果?去掉
-i,加上cat file.txt | sed 's/old/new/g'或直接sed 's/old/new/g' file.txt -
-i有风险:一旦正则写错,原文件直接被覆盖。建议加备份后缀:sed -i.bak 's/old/new/g' file.txt,会生成file.txt.bak
替换时匹配不到字符串的常见原因
不是 sed 不行,是正则或上下文没对上。最常踩的坑是特殊字符没转义、空格/换行干扰、大小写不一致。
- 点号
.、星号*、问号?、括号()等在基本正则里是元字符,要字面匹配就得加反斜杠:sed 's/a\.b/c/g'(匹配a.b,不是a任意字符b) - 想忽略大小写?用
i标志:sed 's/ERROR/error/gi' - 目标字符串含换行或制表符?
sed默认按行处理,无法跨行匹配。这种情况得换perl或先用tr预处理 - 路径或变量里有斜杠
/?改用其他分隔符避免冲突:sed 's|/usr/local|/opt|g'或sed "s|$OLD_PATH|$NEW_PATH|g"
sed -i 在不同系统上的行为差异
Linux(GNU sed)和 macOS(BSD sed)的 -i 参数语义不同,混用会导致命令失败或意外截断文件。
- GNU sed(大多数 Linux 发行版):
sed -i后可不带参数,sed -i 's/a/b/g' f合法 - BSD sed(macOS):
-i必须带一个字符串参数,哪怕为空:sed -i '' 's/a/b/g' f,漏掉空字符串会报错sed: 1: "s/a/b/g": invalid command code s - 写跨平台脚本?统一用
sed -i.bak 's/.../.../g' file,再手动删备份;或改用perl -i -pe(行为更一致) -
sed -i修改的是文件 inode,不是“重写文件”。如果文件被其他进程持续写入(如日志),可能引发竞态——这不是 bug,是设计使然
需要全局替换但只改某几行怎么办
sed 支持地址定界,不必靠管道+grep筛行再交给 sed,既慢又容易出错。
- 按行号范围替换:
sed '5,10s/old/new/g' file(第 5–10 行) - 按匹配行替换:
sed '/^Error:/s/ERROR/error/g' file(仅以Error:开头的行) - 组合条件:先匹配某行,再往后 3 行内替换:
sed '/start/,+3s/foo/bar/g' file - 注意:地址范围内的
s///仍受g控制。不加g只换每行第一个匹配;加了才全换
sed 没法解析嵌套结构;或者日志里时间戳格式多变,单条命令兜不住。这时候硬刚 sed 不如切到 awk 或临时用 Python 处理。










