解析变更日志并提取版本的变更

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),以免打印标题行本身。 换句话说:包含1p 表示后续行已经输入了特定于版本的感兴趣块,并且应该(可能)打印其行。

如果条件匹配,条件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"

【讨论】:

不错;不知道这种变更日志格式。

以上是关于解析变更日志并提取版本的变更的主要内容,如果未能解决你的问题,请参考以下文章

如何找到大量的 Ruby 版本变更日志?

2023年PMP考生|考前必练全真模拟题分享,附答案解析

canal搭建实例

TiCDC 源码阅读TiCDC 集群工作过程解析

TiCDC 源码阅读TiCDC 集群工作过程解析

Elasticsearch7.8.0版本进阶——持久化变更