仅在第一个匹配模式之前插入新行

仅在第一个匹配模式之前插入新行

我的输入文件包含如下数据

acb/xyz/row<t>
acb/xyz/row<t>
abc/xyz/row<b>
abc/xyz/row<b>
abc/xyz/row<0>
abc/xyz/row<0>
abc/xyz/row<1>
abc/xyz/row<1>
abc/xyz/row<2>
abc/xyz/row<2>
abc/xyz/row<3>
abc/xyz/row<3>
abc/xyz/row<4>
abc/xyz/row<4>

所以我希望输出如下所示:

#Sector Top
acb/xyz/row<t>
acb/xyz/row<t>
#Sector Bottom
abc/xyz/row<b>
abc/xyz/row<b>
#Sector 0
abc/xyz/row<0>
abc/xyz/row<0>
#Sector 1
abc/xyz/row<1>
abc/xyz/row<1>
#Sector 2
abc/xyz/row<2>
abc/xyz/row<2>
#Sector 3
abc/xyz/row<3>
abc/xyz/row<3>
#Sector 4
abc/xyz/row<4>
abc/xyz/row<4>
  • 上面显示的每个扇区包含多行,这里我只显示了每个扇区 2 行。
  • 有顶部、底部和从0到30个扇区,这里我最多显示了4个扇区。

我尝试使用 sed 命令来获取其中一个扇区:

sed '/row<1>/i #Sector 1' myfile

这给了我这样的输出:

#Sector 1
abc/xyz/row<1>
#Sector 1
abc/xyz/row<1>

我不需要在每场比赛前换行,只需要在所有部分的第一场比赛前换行。

答案1

使用任何 awk:

$ cat tst.awk
BEGIN {
    FS = "[<>]"
    map["t"] = "Top"
    map["b"] = "Bottom"
}
{
    sector = $(NF-1)
    if ( sector != prev ) {
        print "#Sector", (sector in map ? map[sector] : sector)
        prev = sector
    }
    print
}

$ awk -f tst.awk file
#Sector Top
acb/xyz/row<t>
acb/xyz/row<t>
#Sector Bottom
abc/xyz/row<b>
abc/xyz/row<b>
#Sector 0
abc/xyz/row<0>
abc/xyz/row<0>
#Sector 1
abc/xyz/row<1>
abc/xyz/row<1>
#Sector 2
abc/xyz/row<2>
abc/xyz/row<2>
#Sector 3
abc/xyz/row<3>
abc/xyz/row<3>
#Sector 4
abc/xyz/row<4>
abc/xyz/row<4>

答案2

您可以使用N;P;D循环来执行此操作,并且仅在行号确实更改时sed插入行:#Sector

sed -E 'N;P;/^(.*)\n\1/D;s/.*(\n.*)(row<)([0-9bt])*>/#Sector \3\1\2\3>/;P;D'

现在我们需要为topandbottom部分添加处理,如下所示:

sed -E -e '1i #Sector top' -e 'N;P;/^(.*)\n\1/D;s/.*(\n.*)(row<)([0-9bt])*>/#Sector \3\1\2\3>/;s/#Sector b/&ottom/;P;D'

详细解释:

  • 选项-E是使输出更具可读性。相反,您还可以为这些(…)部分添加八个反斜杠
  • 1i #Sector top只需添加第一个扇区标头
  • 现在我们总是附加Next 行以始终一起处理两行并P打印第一行
  • /^(.*)\n\1/是第一行重复的表达式,因此没有理由插入节标题,因此我们D删除第一行以继续第二行
  • 现在一些正则表达式魔法:s/.*(\n.*)(row<)([0-9bt])*>/#Sector \3\1\2\3>/用节标题和第三()对中提取的行号替换第一行(已经打印!)
  • 最后简单地将更改bbottoms/#Sector b/&ottom/
  • P并通过打印第一行并D删除它以继续第二行来关闭循环

答案3

使用GNUsed

$ sed -Ez 's/(\S+row<([^>]*)>)(.*\1)?/#Sector \2\n&/g;s/\<t\>/Top/;s/\<b\>/Bottom/' input_file
#Sector Top
acb/xyz/row<t>
acb/xyz/row<t>
#Sector Bottom
abc/xyz/row<b>
abc/xyz/row<b>
#Sector 0
abc/xyz/row<0>
abc/xyz/row<0>
#Sector 1
abc/xyz/row<1>
abc/xyz/row<1>
#Sector 2
abc/xyz/row<2>
abc/xyz/row<2>
#Sector 3
abc/xyz/row<3>
abc/xyz/row<3>
#Sector 4
abc/xyz/row<4>
abc/xyz/row<4>

答案4

下面的脚本将在 bash shell 中运行

#!/bin/bash
awk 'BEGIN{ FS="/" }
{a=$3;
    if(a != b)
        print "Sector " substr(a,5,1)"\n" a
    else
        print a;
    b=$3}' myfile.txt

相关内容