文件批处理

在整理网站文档时,发现需要替换飞鸟集文件中的一部分字符(其实是单词写错了😅️),但总共300多个文件,考虑到时间成本,我觉得还是现学一下程序批处理比较划算。搜了下Linux下文件的批处理,做个记录。

首先,要替换一个文件中的某一段字符串可以用以下命令:

1
sed -i "s/oldstring/newstring/g" file_name

有特殊字符时注意转义,可使用正则表达式进行匹配。

其次,要批量替换,只需将file_to_modify替换为要操作的文件列表即可。
在我的问题中目录下所有的md文件都需替换,直接使用*.md匹配即可:

1
sed -i "s/Peom/Poem/g" *.md

对于复杂情况,文件列表可能还需要通过grep等命令来进行匹配获取

之后还有一个问题,开始图方便所有文章的创建日期设的都是同一天,现在想修改成每天一篇,需要将所有文章中的日期依次进行替换。
这个一行代码解决不了,不过也不复杂。首先我需要知道在初始日期之后特定天数的日期是多少,之后用循环依次进行替换就可以了。
获取所对应日期并格式化:

1
date -d "2014-07-04+ 100 days" +%Y-%m-%d

使用之前的命令进行替换:

1
sed -i "s/2015-07-20 .*/$(date -d "2014-07-04+ 100 days" +%Y-%m-%d) 17:00:00/g" 1.md

最后将代码放入循环:

1
2
3
4
5
6
7
8
9
#!/bin/bash

for (( i=1; i<=325; i=i+1 ))
do
#sed -i "s/2015-07-20 .*/$(date -d "2014-07-04+ $i days" +%Y-%m-%d) 17:00:00/g" $i.md
#t=(date -d "2014-07-04 + $i days" +%Y-%m-%d) #will get strange result
t=$(date -d "2014-07-04 + $i days" +%Y-%m-%d)
sed -i "s/2015-07-20 .*/$t 17:00:00/g" $i.md
done

运行代码,1秒钟完成操作,赞!


2018.05.03更新
为了实现KaTeX的支持,用markdown-it替换了默认的marked,公式显示正常了但出现了其他问题。

  • 首先是,当插入的图片文件名或路径名中含有空格时,图片无法正常显示,需要手动去掉多余的空格。文件名中的空格可以两类,一种是数字编号后面跟的空格,直接移除即可;其余的是单词之间的空格,需要替换为下划线。

首先修改文件名

1
2
rename 's/\. /\./g' * #移除文件名中.后面的空格
rename 's/ /_/g' * #将文件名中其余空格替换为_

之后修改Markdown文件

1
2
sed -i '/^\!.*)$/s/\. /./g' *.md   #移除.后面的空格
sed -i '/^\!.*)$/s/ /_/g' *.md #将其余空格替换为_

这里修改文件用到的命令格式为:

1
sed -i '/pattern/s/pattern_string/newstring/g' file_name

该命令首先会找到文件中满足pattern的行,之后对这些行执行进一步的操作。这里的操作是字符替换:将满足pattern_string的字符串替换为newstring。此外还可以通过大括号{}来一次执行多条命令,因此上面个的两条命令可以简化为一条:

1
sed -i '/^\!.*)$/{s/\. /./g; s/ /_/g}' *.md

由于.是位于数字后面的,更精确的可用以下代码处理,这里用到了正则表达式的分组与引用:

1
sed -i '/^\!.*)$/{s/\([0-9]\)\. /\1./g; s/ /_/g}' *.md

而如果要恢复原来文件可使用:

1
sed -i '/^\!.*)$/{s/\([0-9]\.\)/\1 /g; s/_/ /g}' *.md

其次是,图片位于HTML布局代码(居中)内,且插入图片的行与HTML代码间没有空行,图片无法显示。NexT主题默认图片就是居中的,不需布局代码,直接删除即可。

1
2
sed -i '/<center>/d' *.md    #d表示删除匹配的行
sed -i '/\*\*.*\*\*/,/<\/center>/d' *.md #/patten/,/patten/匹配连续多行,此处删除连续两行

最后是当文本位于HTML布局代码(右对齐)内,文字不会换行。将使用的段落标签<p>...</p>替换为可以保留格式的预格式化文本标签<pre>...</pre>

1
2
sed -i 's/<p /<pre /g' *.md
sed -i 's/<\/p>/<\/pre>/g' *.md

递归处理所有子目录文件:

1
2
#find . -name '*.md' -print0 | xargs -0 sed -i 's/\[Notes,/\[Learning,/g'
find . -name '*.md' -exec sed -i 's/\[Notes,/\[Learning,/g' {} +