如何用Bash正则表达式惰性解析HTML中的首个变更列表?
在Bash脚本中解析HTML提取首个变更列表的方法
你现在需要从changes.html里提取最顶部的那个<ol>列表里的<li>内容,之前尝试用Bash正则遇到了问题,我来帮你梳理下问题所在,再给出几个靠谱的解决方案。
先说说你之前脚本的问题
- 文件读取方式导致换行丢失:用
$(< ~/Documents/outfile.html)读取文件时,Bash会把所有换行符替换成空格,整个HTML变成一长串文本,这就破坏了原本的块结构,正则自然没法正确匹配单个<ol>块。 - Bash正则不支持非贪婪匹配:Bash的扩展正则表达式(ERE)不支持
.*?这种惰性匹配语法,所以即使你写了.*,它也会贪婪地匹配到最后一个符合条件的位置,导致匹配范围超出第一个列表。 - 正则表达式的捕获逻辑问题:你写的
(<ol><li>.*</li></ol>)?,在换行丢失的情况下,根本没法精准匹配到第一个列表的内容,所以捕获组是空的。
解决方案
方法1:用sed处理(纯Bash环境可用)
sed是处理文本的常用工具,我们可以用它定位第一个<ol>到</ol>的块,然后提取里面的<li>内容:
sed -n ' /<ol>/,/<\/ol>/ { # 跳过<ol>和</ol>本身的行 /<ol>/! { /<\/ol>/! { # 提取<li>标签里的文本 s/.*<li>\(.*\)<\/li>.*/\1/p } } # 遇到第一个</ol>就退出,避免匹配后续列表 /<\/ol>/q } ' changes.html
运行这个命令后,就能输出第一个列表里的两行文本:
Recent Text line 1 Recent Text line 2
方法2:用awk处理(同样是系统自带工具)
awk的逻辑更直观,通过标记位来控制是否处理内容:
awk ' # 遇到第一个<ol>时,开启标记并跳过当前行 /<ol>/{flag=1; next} # 遇到</ol>时直接退出,只处理第一个列表 /<\/ol>/{exit} # 标记开启且行包含<li>时,提取文本 flag && /<li>/{ sub(/.*<li>/, "", $0) # 去掉<li>之前的所有内容 sub(/<\/li>.*/, "", $0) # 去掉</li>之后的所有内容 print } ' changes.html
方法3:用专业HTML解析工具(推荐,更稳定)
正则处理HTML其实是不太靠谱的(比如标签里多了空格、属性就会失效),更推荐用专门的HTML解析工具,比如pup(需要先安装,比如用apt install pup或者brew install pup):
pup 'h2:first-of-type + ol li text{}' changes.html
这个命令通过CSS选择器精准定位:选择第一个<h2>后面紧邻的<ol>里的所有<li>,然后提取它们的文本内容,结果完全符合你的需求,而且不怕HTML格式的小变动。
内容的提问来源于stack exchange,提问作者Alexander Zhak
相关产品推荐
相关产品推荐

