我正在使用某种模式在 Git 中执行提交消息,以简化新版本 (https://stackoverflow.com/a/5151123/520162) 的更改日志的创建。
应该纳入我的更改日志的每个更改都以 CHG
、NEW
或 FIX
为前缀。
在生成我的更改日志时,我为每个修订版使用以下命令打印出我要解析的修订版:
git show --quiet --date=short --pretty=format:"%cd %an %s%n%n%w(100,21,21)%b%n" $CURRENTREVISION
主体(%s
)持有修改的主体。
接下来,我使用 SED 修改生成的输出,以便它们符合我的更改日志文件的需求。
现在,碰巧在主题行中,多次出现 CHG
,NEW
或FIX
。我的主题输出如下所示:
DATE NAME FIX first change NEW second change CHG third change
我想在除第一次出现的关键字之外的所有关键字前面加上换行符,以便每个CHG
、NEW
或FIX
都开始一个新行:
DATE NAME FIX first change
NEW second change
CHG third change
为了实现这一目标,我必须告诉 SED 什么?
sed
不是最合适的工具
有了awk
,它看起来像这样。
awk '{n=0; for (i=1; i<=NF; i++) {if ($i ~ /(NEW|FIX|CHG)/) {$i=(n++?"n ":"")$i}}}7'
-
n=0
(重新)设置标志 -
for (i=1; i<=NF; i++)
遍历生产线的每个字段 -
if ($i ~ /(NEW|FIX|CHG)/)
字段是否为标记之一-
$i=(n++?"n ":"")$i
通过添加适当的前导空格(或无)来更新字段
-
-
7
真实 y 模式打印出当前行。
awk '{while(++i<=NF){if($i~/FIX|NEW|CHG/){if(f){$i="n"$i}else{f=1}}}}1'
甚至更小:
awk '{while(++i<=NF){if($i~/FIX|NEW|CHG/){if(f++){$i="n"$i}}}}1'
例:
$echo "DATE CH NAME FIX first change NEW second change CHG third change" | awk '{while(++i<=NF){if($i~/FIX|NEW|CHG/){if(f){$i="n"$i}else{f=1}}}}1'
DATE CH NAME FIX first change
NEW second change
CHG third change
从1st to last
字段开始。 对于与 3 种模式中的任何一种匹配的字段,我们检查是否f=1
,在第一个匹配的情况下,这将为 false。 由于我们正在做 f++
,对于下一场比赛,它将是真的,因此"n"
将被添加在前面。
sed '/^DATE NAME/ {
:cycle
s/(.{1,}) (FIX .*)/1
2/g
t cycle
s/(.{1,}) (NEW .*)/1
2/g
t cycle
s/(.{1,}) (CHG .*)/1
2/g
t cycle
s/n/& /g
s/n */ /
}' YourFile
类似于 posix 版本(在 GNU sed 上--posix
)。
一个简单的
s/(.{1,}) ((CHG|FIX|NEW) .*)/1
2/g
t cycle
可以用允许|
的 GNU sed 替换前 3 个s///
我用第一/^DATA NAME/
作为过滤器保护了一点,但如果只处理这种线,就不需要这个(和相关{
}
)
sed
听起来不像是这项工作的正确工具。 sed
中保存的状态非常有限,您的目标需要一个计数器,这在sed
中相当困难。 我想你以后不会乐意维护你的代码。
相反,我认为也许Perl
是一个很棒的工具。
像这样:
while(<STDIN>){
my @matches = m/^(.*?)((?:FIX|NEW|CHG).*?)*$/;
my $date_name = unshift @matches; # only FIX, NEW, CHG remains now
print $date_name, unshift @matches;
while (@matches) { print "tt", unshift @matches; }
}
管道输入原始数据,然后重定向到外壳中的文件。