简体   繁体   English

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

[英]How do I match all but the first matches in a line with sed?

I'm doing my commit messages in Git with a certain pattern to ease creation of a changelog for new releases ( https://stackoverflow.com/a/5151123/520162 ). 我正在使用某种模式在Git中执行提交消息,以简化为新版本创建更改日志( https://stackoverflow.com/a/5151123/520162 )。

Every change that should be taken into my changelog gets prefixed with CHG , NEW or FIX . 应该在我的变更日志中进行的每个更改都以CHGNEWFIX作为前缀。

When it comes to generation of my changelog, I print out the revisions I'm going to parse using the following command for each revision: 对于生成变更日志,我使用以下命令为每个修订版打印要解析的修订版:

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

The subject ( %s ) holds the subject of the modification. 主题( %s )拥有修改的主题。

Next, I'm using SED to modify the generated outputs so that they fit the needs of my changelog file. 接下来,我使用SED修改生成的输出,以使其满足我的变更日志文件的需求。

Now, it happens that in the subject line, there are multiple occurrences of CHG , NEW or FIX . 现在,发生在主题行中,有多次出现CHGNEWFIX My output of the subject looks like this: 我对该主题的输出如下所示:

DATE NAME FIX first change NEW second change CHG third change

I'd like to prefix all but the first occurrence of my keywords with a newline so that each CHG , NEW or FIX starts a new line: 我想在我的关键字(除了第一次出现的关键字之外)以外的所有单词前加一个换行符,以便每个CHGNEWFIX开始一个新行:

DATE NAME FIX first change
          NEW second change
          CHG third change

What do I have to tell SED in order to achieve this? 为了达到这个目的,我必须告诉SED什么?

sed isn't the most appropriate tool for this sed不是最合适的工具

With awk it would look like this. 使用awk ,它将看起来像这样。

awk '{n=0; for (i=1; i<=NF; i++) {if ($i ~ /(NEW|FIX|CHG)/) {$i=(n++?"\n          ":"")$i}}}7'
  • n=0 (re)set a flag n=0 (重新)设置一个标志
  • for (i=1; i<=NF; i++) loop over every field of the line for (i=1; i<=NF; i++)在行的每个字段上循环
  • if ($i ~ /(NEW|FIX|CHG)/) if the field is one of the markers if ($i ~ /(NEW|FIX|CHG)/)如果该字段是标记之一
    • $i=(n++?"\\n ":"")$i update the field by adding the appropriate leading space (or none) $i=(n++?"\\n ":"")$i通过添加适当的前导空格(或不添加$i=(n++?"\\n ":"")$i更新字段
  • 7 truth-y pattern to print out the current line. 7真-y模式打印出当前行。
awk '{while(++i<=NF){if($i~/FIX|NEW|CHG/){if(f){$i="\n"$i}else{f=1}}}}1'

or even smaller: 甚至更小:

awk '{while(++i<=NF){if($i~/FIX|NEW|CHG/){if(f++){$i="\n"$i}}}}1'

Example: 例:

$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

Go from 1st to last fields. 1st to last1st to last for whichever field matching either of the 3 patterns, we check if f=1 , which will be false in case of the first match. 对于匹配这3个模式中的任何一个的字段,我们都会检查f=1 ,如果第一个匹配,则为false。 since we r doing f++ , for next matches it will be true and hence "\\n" will be added before. 由于我们正在做f++ ,对于下一个匹配,它将为true,因此将在前面添加"\\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

something like that for posix version ( --posix on GNU sed). 类似于posix版本(在GNU sed上为--posix )。

a simple 一个简单的

   s/\(.\{1,\}\) \(\(CHG|FIX|NEW\) .*\)/\1\
\2/g
   t cycle

could replace the 3 first s/// with a GNU sed taht allow the | 可以用GNU sed替换第三个s///允许|

I secure a bit with the first /^DATA NAME/ as filter but if only this kind of line is treated, no need of this (and associated { } ) 我用第一个/^DATA NAME/作为过滤器来确保一点安全性,但是如果只处理这种类型的行,则不需要此(以及相关的{ }

sed doesn't sound like a right tool for this work. sed听起来不适合这项工作。 the state preserved in sed is very limited and your goal needs a counter, which is fairly difficult in sed . sed保存的状态非常有限,您的目标需要一个计数器,这在sed相当困难。 i think you won't be happy to maintain your code afterwards. 我认为您以后不愿意保留您的代码。

instead, i think maybe Perl is a fantastic tool for it. 相反,我认为Perl可能是一个很棒的工具。

something like this: 像这样的东西:

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; }
}

pipe in your original data, and redirect out to file in shell. 用管道传输原始数据,然后重定向到Shell中的文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用sed命令删除一行中除前三个字符外的所有字符? - How do I use the sed command to remove all but the first three characters in a line? SED:同一行上的多个模式,如何匹配/解析第一个 - SED: multiple patterns on the same line, how to match/parse first one 如何使用sed匹配并保持第一个数字在一行? - How to match and keep the first number in a line using sed? sed 提取 2 个字符串之间的一行上的所有匹配项 - sed extract all matches on a line between 2 strings sed:需要删除除了匹配字符串的第一行或最后一行之外的所有行 - sed : Need to remove all lines except first or last line that matches a string 如何删除与我提供的文本匹配的前 2 行(使用 sed )? - How do i delete first 2 lines which match with a text given by me ( using sed )? 如何使我的Access VBA正则表达式返回所有可能的匹配而不是仅返回第一个匹配? - How can I have my Access VBA regex return all possible matches instead of only the first match? 使用sed或awk,如何从当前行的末尾匹配回指定的字符? - With sed or awk, how do I match from the end of the current line back to a specified character? 如何使用sed仅替换特定范围的正则表达式匹配? - How do I replace only a specific range of regex matches with sed? 如何用/替换sed行 - How do I replace a line with sed with /
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM