sed默认不修改原文件,需加-i选项;macos需sed -i '',linux直接sed -i;推荐用#作分隔符避免转义;整行替换用c\命令更精准;批量处理用find -exec sed {} +更安全。

sed 替换不生效?默认只处理标准输入,没加 -i 就不会改原文件
很多人跑完 sed 's/old/new/g' 发现文件一点没变——因为 sed 默认是“只读模式”,输出到终端,不碰原文件。必须加 -i 才能就地修改。但注意:-i 在 macOS 和 Linux 行为不同:Linux 下直接写 sed -i 's/old/new/g' file.txt 即可;macOS(BSD sed)要求带空字符串参数:sed -i '' 's/old/new/g' file.txt,否则报错 command a expects \ followed by text。
-
-i后不跟后缀 → 直接覆盖原文件(无备份),高危操作,建议先试-i.bak - 批量处理多个文件时,
sed -i 's/.../.../g' *.txt是安全的,shell 会自动展开通配符 - 如果路径含空格或特殊字符,用
find ... -exec sed -i ... {} +更稳,避免 shell 分词问题
替换含斜杠 / 的路径或 URL?用其他分隔符避开转义地狱
写 sed 's/usr/local/bin/\/opt\/bin/g' 不仅难读,还容易漏掉某个 \/ 导致语法错误。其实 sed 支持任意分隔符,只要和 s 命令后的第一个字符一致就行。换成 # 或 |,路径直接写,不用转义:
sed -i 's#/usr/local/bin#/opt/bin#g' config.conf
这个技巧在处理 Docker 镜像名、HTTP URL、JSON 路径时特别省心。但注意:分隔符本身如果出现在替换内容里,还得转义,比如想把 foo|bar 换成 baz|qux,用 | 当分隔符就得写成 s#foo\|bar#baz\|qux#g。
- 常用替代分隔符:
#(最推荐)、|、@、_ - 别用
/、&、\这些在正则里有特殊含义的字符当分隔符,除非你清楚后果 - 如果内容来自变量(如
$PATH),优先考虑perl -i -pe或awk,避免 shell 展开和 sed 解析双重逃逸
想替换整行匹配的内容?别只盯着 s///,sed '/pattern/c\new line' 更精准
有时候要整个删掉某行再替换成固定内容,比如把所有 debug = false 行换成 debug = true。用 s/debug = false/debug = true/ 会误伤 log_debug = false 这类子串。这时用地址匹配 + 行替换命令更可靠:
sed -i '/^debug = false$/c\debug = true' settings.ini
c\ 表示“change this line”,后面紧跟新内容,^ 和 $ 锁定整行,避免部分匹配。它比 s/// 少一层正则捕获开销,也更直观。
-
/pattern/d删除整行,/pattern/a\text在匹配行后追加,/pattern/i\text在前面插入 - 多个条件组合?用
-e串联:sed -i -e '/^host:/c\host = localhost' -e '/^port:/c\port = 8080' conf.yml - 注意:Windows 换行符(
\r\n)会导致^$失效,先用dos2unix或tr -d '\r'清理
批量替换跨多级目录?find + sed 组合要注意 -exec 的结尾符号
想改 src/ 下所有 .py 文件里的 print 为 logging.info,写成 find src -name "*.py" | xargs sed -i 's/print/logging.info/g' 看似合理,但文件名含空格时会崩。正确姿势是用 -exec 并以 + 结尾:
find src -name "*.py" -exec sed -i 's/print/logging.info/g' {} +
{} + 让 find 把一批文件名一次性传给 sed,效率高且安全;用 {} \; 则每个文件单独调用一次 sed,慢且容易触发系统参数限制。
- 如果要排除某些目录(如
venv),加-not -path "*/venv/*" - 替换前建议先用
find ... -exec grep -l "pattern" {} +确认目标范围,避免误操作 - 某些老旧系统(如 CentOS 6)的 find 不支持
+,只能退化为\;,此时务必加2>/dev/null忽略权限错误提示
真正麻烦的是嵌套引号、变量插值、多层转义——这些地方 sed 很快就力不从心。一旦需求变复杂(比如“只替换函数体内的字符串”),该切到 perl 或写个 Python 脚本了,别硬撑。










