通过实例掌握流编辑器sed
缘由
由于Hugo对Markdown的解析和LaTeX存在诸多冲突。比如:当LaTex中出现\\、\{、\}之类的东西,Hugo就无法正常解析数学公式。
解决方案之一就是用Hugo的shortcodes机制,在md文件中用形如{{< katex [display] >}}latex code{{< /katex >}}格式。
这样一来,网站显示正常了,但在本地Typora就无法识别了。 个人体验不好。
于是我想到用流编编器sed对md内容进行替换。 我以前用sed都是简单的情况,复杂需求我就不会用了。 于是有了此文。
需求
利用Hugo发布到站点前:将$latex code$,置换成 {{< katex [display] >}}latex code{{< /katex >}}。
用Typora写作编辑前: 将 {{< katex [display] >}}latex code{{< /katex >}},置换成 $latex code$。
注意:置换时,同时要跳过代码块不处理。
我写成的代码(后面将逐项解释,备忘)
#!/bin/bash
# md文件递归
function action(){
    for file in `ls $1` 
    do
        if [ -d $1"/"$file ] 
        then
            action $1"/"$file
        elif [ "${file#*.}"x = "md"x ]
        then
            # 方便发布到gitee
            sed -i '/```/ { :begin1; /```.*```/! { $! { N; b begin1 }; }; n; }; /\$\$/ { :begin2; /\$\$[^$]*\$\$/! { $! { N; b begin2 }; }; }; s/\$\$\(\n[^$]*\n\)\$\$/{{< katex display >}}\1{{< \/katex >}}/g; s/\$\$\([^$]*\)\$\$/{{< katex >}}\1{{< \/katex >}}/g; s/!\[.*\](\.\.\/images\//
把上面代码中SED部分单独提出来,写成方便阅读的形式,并逐行解释:
# 正则识别代码块的开始界定符
/```/ {     
	:begin1
	# 正则识别完整代码块
	/```.*```/! { 
		# 没能匹配代码块,则读取下行,附加到“模式空间”
		$! { N; b begin1 } 
	} 
	# 成功匹配代码块,则读取下行,清空“模式空间”
	n; 
} # 上面这段代码目的: 跳过代码块```code```
# 正则识别标准数学公式开始界定符
/\$\$/ { 
	:begin2 
	# 正则识别完整的数学公式块(界定符)
	/\$\$[^$]*\$\$/! { 
		# 没能数学公式块,则读取下行,附加到“模式空间”
		$! { N; b begin2 } 
	} 
} 
# 对“(多行)模式空间” 进行置换:块公式的界定符变换
s/\$\$\(\n[^$]*\n\)\$\$/{{< katex display >}}\1{{< \/katex >}}/g
# 对“(多行)模式空间” 进行置换:内联公式的界定符变换
s/\$\$\([^$]*\)\$\$/{{< katex >}}\1{{< \/katex >}}/g
# 对“(多行)模式空间” 进行置换:顺带进行链接变换
s/!\[.*\](\.\.\/images\//。 
一旦理解这个例子,我想一般的SED就不在话下。