使用 sed -i 修改文件前须确认备份策略,GNU sed 支持 -i.bak 自动备份,BSD/macOS 要求显式后缀如 -i '';批量操作应优先用 grep -rl 配合 xargs,避免 for 循环在空格或无匹配时出错。

sed -i 直接改文件前必须确认备份策略
不加 -i 时,sed 只输出结果到终端,原文件不动;加了 -i 就真改了。但很多人忽略一点:不同系统对 -i 的行为不一致——GNU sed(Linux)支持 -i.bak 自动备份,而 BSD/macOS 的 sed -i 要求必须带后缀(哪怕空字符串 -i ''),否则报错 sed: 1: "s/old/new/g": invalid command code s。
- 安全做法:统一用
sed -i.bak 's/旧/新/g' file,改完保留file.bak - 批量操作时别省略引号,尤其含空格或特殊字符的路径,如
"$file"必须双引号包裹 - 如果目标是“只改含匹配内容的文件”,不能直接通配
*.conf,得先grep -l筛一遍,否则对不含旧字符串的文件也执行-i,徒增 IO 开销
批量替换多个文件,优先用 grep + xargs 而非 for 循环
for file in *.txt; do sed -i 's/a/b/g' "$file"; done 看似直观,但遇到文件名含空格、换行或无匹配文件时容易崩——shell 展开失败或循环体为空导致语法错误。更稳的方式是让 grep -rl 输出绝对路径列表,再交给 xargs 批量喂给 sed:
- 基本写法:
grep -rl "旧字符串" ./path | xargs sed -i 's/旧字符串/新字符串/g' - 路径含空格?加
-0和grep -z配合:grep -rzl "旧字符串" ./path | xargs -0 sed -i 's/旧字符串/新字符串/g' - 想预览哪些文件会被改?先跑
grep -rl "旧字符串" ./path,别急着管道下去
替换内容含斜杠 / 时必须换分隔符
sed 's/\/var\/log/\/opt\/logs/g' 这种写法不仅难读,还极易漏掉转义斜杠,一出错就是 Unknown option to 's'。sed 允许任意字符作分隔符,只要首尾一致即可:
- 路径替换一律用竖线:
sed -i 's|/var/log|/opt/logs|g' config.sh - URL 替换用井号:
sed -i 's#https://old.com#https://new.com#g' app.json - 避免和内容冲突:如果替换字段本身含
|或#,就换用下划线或百分号,比如s_或s%
正则替换要小心贪婪匹配和边界控制
sed 's/abc/xyz/g' 看似简单,但若原文是 abcdef,它会变成 xyzdef——这常是预期行为;可一旦想只换独立单词 abc,就得加词边界 \b:
- 精确匹配单词:
sed -r 's/\babc\b/xyz/g' file(注意-r启用扩展正则) - 替换行首注释:
sed -i 's/^#.*//g' script.py,但^#不会匹配#(前面有空格),得写成^[[:space:]]*#.* - 数字替换慎用
[0-9]\+:在 macOS 上需写成[0-9]\{1,\},或统一加-E(BSD 兼容)
实际批量替换最麻烦的不是语法,而是确认“哪些文件真要动”“改完是否破坏格式”“有没有隐藏的编码或 BOM 影响匹配”。建议先小范围测试,再用 diff 对比备份与修改后文件,别信一次到位。











