我正在使用某种模式在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?
答案 0 :(得分:2)
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
真实模式打印出当前行。答案 1 :(得分:2)
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
,如果是第一次匹配则为假。因为我们正在进行f++
,对于下一场比赛,它将是真的,因此"\n"
将被添加。
答案 2 :(得分:1)
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 taht替换3 s///
允许|
我使用第一个/^DATA NAME/
作为过滤器保证了一点,但是如果只处理这种行,则不需要这个(以及关联的{
}
)
答案 3 :(得分:0)
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 "\t\t", unshift @matches; }
}
管道原始数据,并重定向到shell中的文件。