sed替换命令基本写法为sed -i 's/原字符串/新字符串/g',常见错误包括分隔符冲突、macOS与GNU sed差异、未转义正则元字符、批量处理风险等,需依场景选用合适分隔符、备份机制及转义方式。

sed 替换命令的基本写法和常见错误
Linux 里 sed 批量替换文本,核心就是 sed -i 's/原字符串/新字符串/g' 这条命令。但很多人一执行就报错,比如 sed: -e expression #1, char 0: no previous regular expression,或者改完文件变空——根本原因是没处理好分隔符和特殊字符。
实际用的时候,/ 是默认分隔符,但只要原字符串或新字符串里含 /(比如路径 /home/user/file.txt),就必须换分隔符,否则会提前截断匹配。推荐统一用 | 或 #,更直观:
sed -i 's|/old/path|/new/path|g' config.confsed -i 's#http://example.com#https://new.site#g' index.html
注意:-i 参数在 macOS 和 GNU sed 中行为不同,macOS 必须带后缀(如 -i ''),否则报错 sed: 1: "s/...": command a expects \ followed by text;而 Linux(GNU)支持 -i 不带参数,但加空字符串 -i '' 反而更兼容。
如何安全地批量替换多个文件
直接对 *.txt 通配执行 sed -i 's/foo/bar/g' *.txt 看似方便,但有三个现实风险:文件名含空格会断开、没有备份、遇到只读文件直接失败退出。
更稳妥的做法是用 find 配合 -exec,并强制生成备份:
-
find . -name "*.md" -exec sed -i.bak 's/Python/Python 3/g' {} \;—— 每个文件都生成.bak备份 - 如果只想改当前目录(不含子目录),加
-maxdepth 1 - 替换前先预览效果:
sed 's/foo/bar/g' file.txt(不加-i)
别忽略权限问题:如果某文件不可写,sed -i 会静默跳过(GNU sed)或报错中断(部分版本)。建议先用 ls -l 粗筛,或加 2>/dev/null 屏蔽错误流(仅用于确认范围)。
正则元字符没转义导致替换失效
sed 默认用基础正则(BRE),.、*、[、^、$ 这些都有特殊含义。想替换成字面意思,必须加反斜杠转义,否则可能全文件乱匹配。
例如把 score: 95 改成 score: 100,写成 sed -i 's/score: 95/score: 100/g' 没问题;但若原串是 version: 1.2.3,写成 s/version: 1.2.3/version: 2.0.0/g 就会把所有含 1x2x3 的行都中枪(因为 . 匹配任意字符)。
- 正确写法:
sed -i 's/version: 1\.2\.3/version: 2\.0\.0/g' - 要匹配行首的
# TODO?得写s/^# TODO/# DONE/g,^要保留,不能写成\^ - 如果要替换含换行的内容,
sed本身不擅长,该换awk或perl -0777
Mac 上 sed 和 Linux 不兼容的几个硬伤
macOS 自带的是 BSD sed,和 GNU sed 在关键地方不一致:不支持 -r(扩展正则),-i 必须带后缀,且某些替换语法(如 \1 引用捕获组)行为略有差异。
跨平台脚本最省事的解法是安装 GNU sed:brew install gnu-sed,然后用 gsed 命令(或加 alias sed=gsed)。但如果你只能用系统自带 sed,就得守规矩:
-
sed -i '' 's/old/new/g' file——-i ''是强制要求,空字符串不能省 - 想用
+表示“一个或多个”,得写成\+(BRE 规则),不能用-r - 捕获组用
\(...\),引用用\1,不是$1
最容易被忽略的是:BSD sed 对空行和结尾换行的处理更严格,有时 echo "a" | sed 's/a/b/' 在 macOS 上可能多出一个空行,检查输出时最好加 cat -A 看控制符。









