解析变更日志并提取版本的变更
Posted
技术标签:
【中文标题】解析变更日志并提取版本的变更【英文标题】:Parse a changelog and extract changes for a version 【发布时间】:2017-03-19 21:57:02 【问题描述】:我在 markdown 中有一个更改日志文件,其中包含我的应用程序的每个版本之间的所有更改:
## Version 1.0.6
* first change
* second change
* third change
## Version 1.0.5
* first foo change
* second foo change
## Version 1.0.4
* and so on...
我想要的是在 脚本 中提取版本的更改内容。例如,我要提取 1.0.5 版 的更改,所以它应该打印:
* first foo change
* second foo change
理想的方式是./getVersionChanges version filename
这两个参数:
version
: 提取更改的版本
filename
:要解析的文件名
如何使用 sed、awk、grep 或其他方式实现此目的?
【问题讨论】:
How to select lines between two patterns?的可能重复 另见***.com/documentation/awk/1403/…和***.com/questions/2227583/… 【参考方案1】:稍微复杂一点的awk
解决方案,
awk -v ver=1.0.5 '
/^## Version / if (p) exit ; if ($3 == ver) p=1; next p && NF
' file
作为脚本getVersionChanges
:
#!/usr/bin/env bash
awk -v ver="$1" '
/^## Version / if (p) exit ; if ($3 == ver) p=1; next p && NF
' "$2"
说明:
正则表达式条件/^## Version /
匹配具有版本特定信息的行块的标题行,方法是在行的开头 (^
) 查找子字符串 ## Version
,如果找到,则执行相关代码块( ...
):
if (p) exit
退出(停止处理),如果 p
(打印)标志先前已设置,因为这意味着块之后感兴趣的块已经到达,即感兴趣的区块现在已被完全处理。
if ($3 == ver) p=1; next
检查标题行上的第三个空格分隔字段 ($3
) 是否与给定的版本号匹配(通过选项 -v ver=1.0.5
传递,因此存储在变量 ver
中),如果是,则设置自定义变量p
,用作指示是否打印一行的标志,到1
并移动到下一行(next
),以免打印标题行本身。
换句话说:包含1
的p
表示后续行已经输入了特定于版本的感兴趣块,并且应该(可能)打印其行。
如果条件匹配,条件p && NF
会隐式打印手头的行,如果设置了打印标志p
并且 (&&
) 手头的行在至少一个字段(基于反映在内置变量NF
中的字段数),即如果该行是非空白,从而有效地跳过块中的空行和全空白行感兴趣。
&&
的两个操作数都使用隐式布尔逻辑:0
的值(一个未初始化的自定义变量,如p
默认为)是隐式假的,而任何 非零 值都隐含地为真。
【讨论】:
当$3 == ver
可以正常工作时,为什么要添加if
..为什么会弄乱代码?其他 if 也一样...
对不起...我不知道没有 if 的代码是否可以工作...没有意识到它在大括号内...
我喜欢使用NF
来跳过空行..+1
@mklement0,正是我想要的,完美运行,谢谢!
感谢您的出色解决方案!我已经更新它以使用 keepachangelog 约定。请参阅下面的答案【参考方案2】:
一个相当短的awk
脚本将提取您想要的块。
#!/bin/sh
awk -v version="$1" '/## Version / printit = $3 == version; printit;' "$2"
一个样本:
$ ./getVersionChanges 1.0.5 filename
## Version 1.0.5
* first foo change
* second foo change
$
【讨论】:
不应该是$3 == v
是$3 == version
下一个命令可以在
中使用,如果意图是跳过版本的行。这就是问题所问的。
我知道我与请求相矛盾,但我认为在输出中包含标头会很有帮助(并且它使代码更简单)。
也很好用,与接受的解决方案的不同之处在于您保留了版本的标题,谢谢。【参考方案3】:
试试这个。您可以将 /tmp/data 替换为您的文件名,将“Version 1.0.5”替换为您的搜索模式。请注意,这不会删除任何空行。
sed '1,/Version 1.0.5/d;/Version/Q' /tmp/data
输出:
* first foo change
* second foo change
说明
默认情况下 sed 将打印这些行。所以我们只是改变逻辑来删除我们不需要的行。
选择第 1 行和模式之间的所有内容并将其删除
1,/Version 1.0.5/d
找到模式后退出
/Version/Q
【讨论】:
很有趣,但为避免误报,您应该 (a) 将版本号中的.
转义为 \.
(这意味着使用来自变量的输入,您必须执行此替换首先以编程方式)和(b)确保版本号也仅在末尾的单词边界上匹配。此外,为了确保在 first 行上也找到了可能的匹配项,范围应以 0
(0,/Version 1\.0\.5\b/
) 开头。以0
开头并使用Q
函数的范围是GNU sed
扩展,因此在BSD/macOS 上需要更精细的解决方案。
我更新了答案以表明它不会去除空行。您指出的其他事情也是正确的。【参考方案4】:
保留更新日志
我在寻找一种从使用keepachangelog 约定编写的变更日志中提取一些发行说明的方法时发现了这个线程。
我已经修改了@mklement0 的答案以使其符合这个约定。
外壳
awk -v ver=1.0.5 '
/^#+ \[/ if (p) exit ; if ($2 == "["ver"]") p=1; next p && NF
' file
脚本
#!/usr/bin/env bash
awk -v ver="$1" '
/^#+ \[/ if (p) exit ; if ($2 == "["ver"]") p=1; next p && NF
' "$2"
【讨论】:
不错;不知道这种变更日志格式。以上是关于解析变更日志并提取版本的变更的主要内容,如果未能解决你的问题,请参考以下文章