我想从压缩合并 GitHub PR 所产生的提交消息字符串中提取 Jira Id。如果存在多个 Jira Id,我想提取第一个。
如何使用 bash 正则表达式、sed、grep、groovy 或任何其他可用的命令行工具来完成此操作?
测试用例:
ABCD-1231 dummy title XYZ-566 (#423)
=> ABCD-1231
[ABCD-1232, XYZ-566] dummy title (#424)
=> ABCD-1232
[ABCD-1233] dummy title (#425)
=> ABCD-1233
ABCD-1234: dummy title (#426)
=> ABCD-1234
XYZ-567 dummy title (#427)
=> XYZ-567
(XYZ-568) dummy title (#428)
=> XYZ-568
"XYZ-569" dummy title (#429)
=> XYZ-569
dummy title XYZ-570 dummy title (#430)
=> XYZ-570
DUMMY title XYZ-571 dummy title (#431)
=> XYZ-571
'feature/XYZ-572' dummy title (#432)
=> XYZ-572
FEATURE|XYZ-573 dummy title (#433)
=> XYZ-573
<Feature\XYZ-574> dummy title (#434)
=> XYZ-574
dummy title FAKE-XYZ-575 dummy title (#435)
=> <nothing>
dummy title abcdXYZ-576 dummy title (#436)
=> <nothing>
在Bash中,
"[^A-Z]*(([A-Z]+-[0-9]+)*.*) \(#([0-9]+)\)"
会失败
并且 bash 似乎不支持如下所示的负向后查找:
".*[^A-Z]*((?<!([A-Z]+)-?)[A-Z]+-[0-9]+).*"
任何人都可以提出解决方案或完成此任务的正确工具吗?
您可以尝试使用 grep
在
-P
上启用 PCRE引擎 选项。这可能取决于您的
grep
版本
服务器。它会让你使用环顾四周。
您还可以使用
-m 1
选项限制匹配行,但它
对我们没有多大帮助,因为提交消息在一行上。但是
-o
选项将仅o输出匹配项。然后我们可以将它传递给
head
,以便仅获取 grep 输出的第一行。
对于图案,我会用
(?<=^|[^\w-])[A-Z]+-\d+
尝试。
我使用了积极的lookbehind来匹配开头
该行或任何字符不是单词或连字符。
我在以下 bash 脚本中测试了您的所有提交消息:
#!/bin/bash
commits=(
"ABCD-1231 dummy title XYZ-566 (#423)"
"[ABCD-1232, XYZ-566] dummy title (#424)"
"[ABCD-1233] dummy title (#425)"
"ABCD-1234: dummy title (#426)"
"XYZ-567 dummy title (#427)"
"(XYZ-568) dummy title (#428)"
'"XYZ-569" dummy title (#429)'
"dummy title XYZ-570 dummy title (#430)"
"DUMMY title XYZ-571 dummy title (#431)"
"'feature/XYZ-572' dummy title (#432)"
"FEATURE|XYZ-573 dummy title (#433)"
"<Feature\XYZ-574> dummy title (#434)"
"dummy title FAKE-XYZ-575 dummy title (#435)"
"dummy title abcdXYZ-576 dummy title (#436)"
)
for (( i=0; i<${#commits[@]}; i++ ))
do
echo ${commits[$i]}
# A) My first attempt, using head to only get the first match.
echo ${commits[$i]} | grep -P -m 1 -o '(?<=^|[^\w-])[A-Z]+-\d+' | head -n1
# B) InSync's more sofisticated solution to match only the first
# occurrence with the help of \K, which resets the starting point
# of the reported match. This is a good way to consume characters
# which we don't want in the output. It's also used because we can't
# solve this with a positive lookbehind as the latter has to be a fixed
# length pattern (not the case because of the ungreedy .*? pattern).
# My positive lookbehind (?<=^|[^\w-]) can also be replaced by a
# shorter negative lookbehind (?<![\w-])
echo ${commits[$i]} | grep -P -m 1 -o '^.*?\K(?<![\w-])[A-Z]+-\d+'
done
谢谢@InSync,您的聪明解决方案不使用
head
和
通过使用 PCRE 的 \K
模式来重置起始点
报告比赛。它用来以一种不贪婪的方式消耗所有的
第一个 Jira Id 之前的字符。我已将其添加到批次中
上面 B) 点下。
输出,A) 和 B):
ABCD-1231 dummy title XYZ-566 (#423)
ABCD-1231
ABCD-1231
[ABCD-1232, XYZ-566] dummy title (#424)
ABCD-1232
ABCD-1232
[ABCD-1233] dummy title (#425)
ABCD-1233
ABCD-1233
ABCD-1234: dummy title (#426)
ABCD-1234
ABCD-1234
XYZ-567 dummy title (#427)
XYZ-567
XYZ-567
(XYZ-568) dummy title (#428)
XYZ-568
XYZ-568
"XYZ-569" dummy title (#429)
XYZ-569
XYZ-569
dummy title XYZ-570 dummy title (#430)
XYZ-570
XYZ-570
DUMMY title XYZ-571 dummy title (#431)
XYZ-571
XYZ-571
'feature/XYZ-572' dummy title (#432)
XYZ-572
XYZ-572
FEATURE|XYZ-573 dummy title (#433)
XYZ-573
XYZ-573
<Feature\XYZ-574> dummy title (#434)
XYZ-574
XYZ-574
dummy title FAKE-XYZ-575 dummy title (#435)
dummy title abcdXYZ-576 dummy title (#436)