每次要进行一些批量的文本处理,例如 sed, awk 处理数据或者涉及到正则表达式的时候,都需要临时去再查一遍资料,看一下怎么用。这里简要记录一下对大量文件进行正则匹配后批量替换文本的方法,方便以后要用的时候回顾一下。

因为 blog 的图片迁到了七牛云上(提供CDN加速服务),原来的图片链接必然要替换成七牛云提供的二级域名,在 markdown 文件中有很多图片的标签,也不可能一个一个手动改,最好是能一个命令下去直接全部修改完毕并且以后也可以很轻松地改成其他域名。

执行的命令如下:

sed -i "s?](.*|pic|?](http://xxx.clouddn.com|pic|?g" `grep "|pic|" -rl ./`

注:本文中所有的 |pic| 其实是 /pic/,这样是为了避免被误替换。也可以通过 grep -v 来手动指定不替换的文件。

markdown 中的图片标签一般的格式是 ![label](http://www.xxx.com/a.jpg),我的图片链接则是都会有一个 pic 的目录前缀。

grep

先看后面,grep "|pic|" -rl ./ 用于递归查找所有含有 |pic| 这个字符串的文件所在路径的路径名,按行显示。

  • -r 参数表示会对目录进行递归查找。
  • -l 参数会输出匹配的文件名

sed

sedawk 都是文本处理的利器。

sed 进行文本替换的常用的格式是 sed "s/aa/bb/g" ./testfile,表示将文件中所有的 aa 替换成 bb, 最后的 g 表示作用域是全局。

这里分隔符用的 /,也可以换成其他符号,比如上面我用的是 ?,只要保证这三个地方的符号一致并且没有歧义即可。

](.*|pic| 是一个正则匹配, . 表示匹配任意一个字符,* 表示匹配0个或多个前面的字符,这里两个合起来就是匹配任意字符串。完整的意思就是匹配以 ]( 开头,以 |pic| 结尾的任意字符串。

](http://xxx.clouddn.com|pic| 是替换后的字符串。

-i 表示将替换后的结果写入文件中,而不是直接输出。

查看修改结果

一开始不确定修改是否正确最好不要给予使用 -i 参数将修改后的结果写入文件,可以将上面的命令换成如下的内容来检查是否替换正确:

sed -n "s?](.*|pic|?](http://xxx.clouddn.com|pic|?gp" `grep "|pic|" -rl ./`

-n 表示静默模式,如果有输出内容的话,不会输出整个文件的内容,而仅仅是匹配的内容。

后面的 gpg 前面说过是表示作用域是全局,p 表示会输出匹配的内容。