最近给博客站点增加了一个独立的页面: 指南 ,用来记录本站点的所有文章,包括发表时间与文章链接,并按照发表时间倒序排列,仅供快速查找以及核对使用。其中,还会有一个文章编号,就是 url 的数字部分,由日期与编号组成,例如 2019050201 表示 2019 年 05 月 02 日发表的第 1 篇文章,这个文章编号对我来说很有用,用来核对查重。但是,为了简化这个页面的整理工作以及后续的自动生成,我需要把这个流程自动化,本文记录实现思路与实现方式。
实现思路
为了简化难度,我准备使用 Shell 解决这个问题。大概思路:遍历目录的文件、解析 id 与 title、搜索匹配指南 index 文件、替换或者追加。
1、遍历指定目录【_post 目录】中的所有 markdown 文件,对每个文件执行 2。
2、对单个文件,使用 grep 正则搜索: ^id: [0-9]{10},使用 awk 获取 id 值,判断 id 值是否在 index 文件中,在则跳过,否则执行 3。
3、再使用 grep 正则搜索: ^title: ,使用 awk 获取 title 值,执行 4,把 id 值和 title 值追加到 index 文件中。
4、先使用 grep id 值 index 文件 搜索 3 中的 id 是否已经在 index 文件中,不在才能追加进去。追加 index 文件时,先重命名 index 文件为 index_bak,逐行读取。对每一行数据使用 grep 正则搜索:
1 | echo $line | grep -E '^- [0-9]{10},\[' | awk -F',' '{print $1;}' | awk -F' ' '{print $2;}' |
如果搜索无内容的直接将当前行写入新文件,命名为 index。再结合使用 awk 获取当前行的 id 值,只要 3 中的 id 值大于此 id 值并且年份一致,则将 3 中的 id 值和 title 值写入新文件【构造特定格式的数据行】,接着再将当前行写入新文件。如果年份一致且 3 中的 id 值最小,则按照 5 写入当年的数据最后一行。
5、相同年份作一个标记,是否已经写入新文件作一个标记,如果遇到读取的下一行已经不是当年的数据【正则搜索无结果】,则把构造的特定格式的数据行写入新文件,再把当前行写入新文件。
6、4 中的文件逐行读取完成后,把 4 中一开始重命名的文件 index_bak 删除,只保留新文件 index,此时 index 文件中已经增加了一行新内容。
具体实现
以下涉及的 Shell 脚本已经被我上传至 GitHub,读者可以提前下载查看:auto_guide.sh ,脚本命名与下文中描述一致。
Shell 脚本内容参考如下【脚本名称为:auto_guide.sh】,注释都已经标明处理逻辑,通俗易懂:
1 | #!/bin/bash |
执行脚本时会打印解析出来的每条 id 与 title,以及写入的原因【比较后写入、最后一条写入】,第一次执行脚本耗时久一点,后续执行会自动跳过已经收集过的,耗时可以忽略。
由于实现思路简化了,所以要求 index 文件在每一年都至少已经有一个完整的记录,否则没法对比写入。
注意,正则搜索时在必要情况下使用 -E 选项开启扩展模式,否则正则无效,仍旧是普通的字符串。
日期格式的字符串比较大小,由于格式规范,都是十位数字,可以直接转为数字比较,大的就代表日期最新。
当然,日期格式的字符串比较大小,也可以先转为时间戳数字,再进行比较,示例:
1 | date +% s -d '2019010101' |
虽然这种格式得到的结果不是真正的时间戳,但是只要是数字就可以比较了。另外,经过查找帮助手册,没有发现可以指定格式的参数选项,也就是无法把 YYMMddHH 格式的日期字符串转为对应的真实时间戳。

