sed -i 跨平台不兼容且易丢数据:gnu sed 支持 sed -i 's///',bsd sed 必须带备份后缀如 -i.bak;文件名含空格需用 find -print0 | xargs -0;替换含斜杠用 # 分隔;务必先测试再加 -i。

sed -i 是最直接有效的方案,但不加判断地跑一遍,大概率会改错、漏改、或在 macOS 上直接报错。
sed -i 在 Linux 和 macOS 上写法不同
sed -i 不是跨平台安全的命令,硬写会翻车:
- Linux(GNU sed):直接
sed -i 's/foo/bar/g' file.txt
- macOS(BSD sed):必须带空后缀,否则报错
command a expects \ followed by text → 正确写法是 sed -i '' 's/foo/bar/g' file.txt
如果脚本要兼顾两者,要么用
perl -i -pe(更统一),要么先检测
sed --version 输出里有没有
GNU 字样再分支处理。
替换含 / 的路径或 URL 时别硬逃逸
写
sed -i 's/\/usr\/local\/bin/\/opt\/bin/g' 容易漏转义、难读、难维护。直接换分隔符:
- 用
#:sed -i 's#/usr/local/bin#/opt/bin#g'
- 用
|:sed -i 's|https://old.com|https://new.org|g'
注意:如果分隔符本身出现在内容里(比如想把
foo|bar 换成
baz|qux),就得转义它:
s#foo\|bar#baz\|qux#g。
避免误替换:用锚点和单词边界
s/debug = false/debug = true/g 会把
log_debug = false 也干掉。更稳妥的方式是加约束:
- 整行匹配:
sed -i '/^debug = false$/c\debug = true' config.ini(c\ 命令直接整行替换)
- 单词边界:
sed -i 's/\bdebug\b/debug_verbose/g' *.py(\b 确保只换独立单词)
- 行首固定前缀:
sed -i 's/^host:.*/host: localhost/' *.yml
正则里的
.、
*、
[ 都要转义才能当字面量用,否则就是通配。
批量处理多个文件时,find + {} + + 是底线配置
sed -i 's/foo/bar/g' *.conf 看似简单,但遇到空格路径、上万个文件、或文件名超长时会失败。生产环境应默认走
find:
- 安全写法:
find . -type f -name "*.conf" -exec sed -i 's/foo/bar/g' {} +
-
{} + 比 {} \; 快得多——前者把一批文件传给一个 sed 进程,后者每个文件都启一次进程
- 如果文件路径可能含换行或空格(极少见但存在),用
find ... -print0 | xargs -0 sed -i ...,但多数运维场景没必要过度防御
真正容易被忽略的是备份和预览:没加
-i.bak 就直接跑,或者没先用
sed 's///g' file.txt | head 看效果,出错就只能靠
git checkout 或祈祷有备份。