用 sed + grep 批量替换目录下文件中的字符串

改代码时经常遇到这种需求:把整个工程里某个旧字符串全部替换成新的,比如交叉编译工具链从 arm-none-linux-gnueabi- 换成 arm-linux-。手工逐个文件改既慢又容易漏,用 sed 配合 grep 一条命令就能搞定。

核心命令

以下命令把当前目录(含子目录)下代码中所有的 arm-none-linux-gnueabi 相关字符串替换掉:

sed -i 's/arm-none-linux-gnueabi-g++/arm-linux-g++\ -O2\ -I\$\(INC\)\ -I\$\(INCSYS\)\ -static/g' `grep arm-none-linux-gnueabi-g++ . -rl`
sed -i 's/arm-none-linux-gnueabi-gcc/arm-linux-gcc\ -static/g' `grep arm-none-linux-gnueabi-gcc . -rl`
sed -i 's/arm-none-linux-gnueabi/arm-linux/g' `grep arm-none-linux-gnueabi . -rl`

同样的套路可以替换任意字符串,比如设备节点名和路径:

sed -i 's/nand1-2/mtd/g' `grep nand1-2 . -rl`
sed -i 's/\/opt\/RTU\/data\/etc/\/mnt\/mtd/g' `grep /opt/RTU/data/etc . -rl`

注意第三条命令覆盖了前两条的范围,所以执行顺序上要先替换更长的、更具体的字符串(-g++-gcc),最后再替换公共前缀,否则前缀先被替换掉,后面就匹配不到了。

配合原理

这条命令能工作,靠的是两个工具各司其职:

  • grep -rl-r 递归搜索当前目录下所有文件,-l 表示只列出包含匹配内容的文件名,而不是打印匹配行。
  • 反引号(`)做命令替换:把 grep 输出的文件列表直接作为参数传给 sed
  • sed -i-i 表示 in-place,直接修改文件内容并写回,而不是把结果打印到屏幕上。

三者串起来就是:grep 找出哪些文件包含目标字符串,sed 负责在这些文件里原地进行替换

替换路径这类含 / 的字符串时,需要对 / 转义(如 \/opt\/);也可以换用其他分隔符来少打转义,例如 sed -i 's#/opt/RTU/data/etc#/mnt/mtd#g'

补充:sed 在行首/行尾添加字符

在每行的行首添加字符(比如 HEAD):

sed 's/^/HEAD&/g' test.file

在每行的行尾添加字符(比如 TAIL):

sed 's/\$/&TAIL/g' test.file

补充:用 sed 清理 Windows 换行符

Unix 系统里每行结尾只有换行符 \n;Windows 系统里每行结尾是回车加换行 \r\n。一个直接后果是:Unix 下的文件在 Windows 里打开时所有文字会挤成一行;而 Windows 下的文件在 Unix 里打开时,每行结尾会多出一个 ^M 符号。

这类问题很适合用 sed 预处理,把 \r 去掉:

sed -i 's/\r//' test.file

小结

  • 字符串替换交给 sed 's/from/to/g' 处理,加 -i 直接改文件。
  • 批量替换的公式:sed -i 's/旧/新/g' \grep 旧 . -rl``。
  • 替换有公共前缀的多个字符串时,先长后短。

   转载规则


《用 sed + grep 批量替换目录下文件中的字符串》 吴杭沉 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
定时删除 30 天前的文件:cron 与 find 定时删除 30 天前的文件:cron 与 find
服务器上的日志文件如果一直不清理,迟早会把磁盘占满。最省心的办法是用 Linux 的 cron job 定期执行一条 find 命令,自动删掉 30 天前的旧文件。本文以每天清理 /logs 目录为例,记录完整的配置过程。 编写清理脚本cr
2020-12-13
下一篇 
ln -s 软链接使用指南与常见误区 ln -s 软链接使用指南与常见误区
在 Linux 下,ln -s 用来创建软链接(也叫符号链接),作用类似 Windows 里的快捷方式:它指向真实的源文件或源目录,访问链接就等于访问源。本文整理了软链接的常见用法、容易踩的坑,以及它与硬链接的区别。 基本用法创建软链接的命
2020-11-29
  目录