1. 文件内容替换:每个Linux用户都绕不过去的日常操作
先说个真实场景。我之前在一家中型公司做运维,每周都要处理大量的配置文件变更、日志脱敏、代码批量调整。刚开始带新人的时候,发现很多刚接触Linux的同事面对“把这台服务器上所有配置文件里的旧域名改成新域名”这类需求,第一反应是打开vim,一个文件一个文件地改。遇到文件多的时候,能折腾一下午,而且大概率会有遗漏。
其实在Linux生态里,文件内容替换早就是一门“老手艺”了,核心工具无非是sed、awk、perl这几样,但用得好和用得烂,效率差距是数量级的。这篇文章不打算写成一本文档手册,而是想结合我自己实际使用中踩过的坑、摸索出来的经验,把文件内容替换这件事聊透。不管你是刚接触命令行的新手,还是已经在生产环境摸爬滚打了一阵子的工程师,这篇文章应该都能给你一点新东西。
先明确一下,这篇文章聊的“文件内容替换”涵盖这几个层面:
- 单个文件中的字符串替换、行替换、按模式替换
- 多个文件的批量替换,以及替换前的过滤筛选
- 正则表达式在替换中的正确使用姿势
- 特殊字符、编码、转义等容易翻车的细节
- 不同工具(sed/awk/perl)在不同场景下的选择逻辑
其实很多时候,一个问题“会不会”是一回事,“能不能在生产环境不出事地用出来”是另一回事。我在生产服务器上因为一条替换命令出过故障,也在脚本里因为转义层级太多排查了一整晚。这些经验,我会原原本本写出来。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. sed基础中的基础:替换命令的语法与设计逻辑
2.1 一行命令的拆解:s命令为什么要这样写
sed里的替换命令基本形式是:
bash复制sed 's/旧内容/新内容/标志' 文件名
这个写法看起来简单,但每一个部分都有讲究。
先看开头的 s,这是“substitute”的缩写,sed用这个字母告诉解释器“我要做替换操作”。接下来的一对斜杠 / 是分隔符,把“旧内容”“新内容”“标志”三部分隔开。旧内容不只是普通字符串,它本质上是一个正则表达式;新内容是替换的目标文本;最后的标志位则决定了这次替换的行为模式。
最常见的标志是 g,表示“global”,意思是这一行里所有匹配到的内容都替换,而不只是第一个:
bash复制sed 's/foo/bar/g' test.txt
如果没有 g,一行里只有第一次匹配到的 foo 会被替换成 bar,后面的保持不变。这个细节很多人第一次用的时候会忽略,导致结果和自己预期的完全不一样。
还有几个标志值得记住。i 表示忽略大小写,n 配合 p 可以只打印被替换过的行(这个组合在调试的时候特别好用)。数字(比如 2)表示只替换这一行中第二次出现的内容,这种需求相对少见,但真要碰到的时候很救命。
从我个人的经验来看,刚开始接触sed的时候不用记太多花哨的写法,把基本替换、全局替换、行范围限定这三样练熟,就已经能覆盖日常80%以上的需求了。
2.2 原地修改:关于 -i 参数的几个关键细节
大多数时候,我们不只是想把替换后的内容打印到屏幕上,而是要直接改文件本身。这时就需要 -i(in-place)参数:
bash复制sed -i 's/foo/bar/g' test.txt
加了 -i 之后,sed会把修改写回原文件。这里有一个特别重要的细节:sed原地的“地”并不是原来的文件,它只是把修改后的内容写到了一个临时文件里,然后再用临时文件替换掉原文件。 这个过程在外人看来是“原地修改”,实际上文件系统的inode已经变了。
什么情况下这个细节会要命?文件权限和属主。如果临时文件创建时继承的权限和原文件不一致,你可能会发现改完文件之后,权限变了。解决方式有两种:
bash复制# 方法一:替换后用 chown/chmod 修正权限
sed -i 's/foo/bar/g' test.txt && chown --reference=test.txt.bak test.txt
# 方法二:在支持的情况下,直接用 -i 的备份文件功能,同时保留原权限
sed -i.bak 's/foo/bar/g' test.txt
第二种写法里,.bak 是备份文件的后缀。执行之后,目录下会生成一个 test.txt.bak,里面是修改前的原始内容,test.txt 则是修改后的结果。这个习惯我强烈建议养成——在生产环境里执行批量替换之前,留一份备份,成本只是几个字节的磁盘空间,但万一替换结果出了问题,你就有一条实实在在的后路。
我见过不止一次,有人在生产环境写配置脚本时用了 sed -i,替换完了发现正则写得有问题,大面积配置被改坏。有备份文件的人花两分钟恢复,没备份的人只能靠git或备份系统,要是这些都没有,就只能手动改回去,那复杂度就不是一个量级的了。
3. 地址与范围:只处理你想处理的那几行
3.1 行号限定、正则匹配和区间控制
sed的能力不只在于“全文替换”,更在于“只替换指定范围的内容”。这个在日常文件内容替换中其实更加实用,因为你经常不是想改整个文件,而是只想改某一节配置、某一段文本。
最简单的范围控制是用行号:
bash复制# 只替换第10行中的 foo
sed '10s/foo/bar/g' test.txt
# 替换第10行到第20行之间的 foo
sed '10,20s/foo/bar/g' test.txt
# 从第10行到文件末尾
sed '10,$s/foo/bar/g' test.txt
注意,这里的行号是替换前的行号,sed每处理完一行之后行号递增。如果你的替换逻辑里改了行的数量(比如删除行),行号会受
