我如何匹配除了sed中一行中的第一个匹配项以外的所有匹配项?

时间:2014-12-08 13:51:21

标签: regex sed git-show

我正在使用某种模式在Git中执行我的提交消息,以便于为新版本创建更改日志(https://stackoverflow.com/a/5151123/520162)。

应该在我的更改日志中进行的每项更改都会以CHGNEWFIX为前缀。

在生成更改日志时,我打印出我要使用以下命令为每个修订解析的修订:

git show --quiet --date=short --pretty=format:"%cd %an %s%n%n%w(100,21,21)%b%n" $CURRENTREVISION

主题(%s)包含修改的主题。

接下来,我正在使用SED修改生成的输出,以便它们符合我的更改日志文件的需要。

现在,在主题行中发生了多次CHGNEWFIX。我的主题输出如下:

DATE NAME FIX first change NEW second change CHG third change

我希望在第一次出现的关键字前加上换行符,以便每个CHGNEWFIX开始换行:

DATE NAME FIX first change
          NEW second change
          CHG third change

为了达到这个目的,我有什么要告诉SED?

4 个答案:

答案 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中的文件。