查找文件中最长的部分

查找文件中最长的部分

我有一个以 SUBBEGIN 开头并以 SUBEND 结尾的文件,但两者之间有很多行。我想获取在 SUBBEGIN 和 SUBEND 之间具有最大行数的任何此类部分。如果我也获得此过滤的命令,这对我会有帮助。一行命令以及供将来使用的脚本。

<SUBBEGIN
        IMSI=XXXXXXXX;
        MSISDN=XXXXXXXXXXXX;
        DEFCALL=TS11;
        CURRENTNAM=BOTH;
        CAT=COMMON;
        TBS=TS11&TS12&TS21&TS22&TS61&BS26&BS2G;
        ODBIC=BAIC;
        ODBOC=BAOC;
<SUBEND
<SUBBEGIN
        IMSI=XXXXXXXX;
        MSISDN=XXXXXXXXXXXX;
        DEFCALL=TS11;
        CURRENTNAM=BOTH;
<SUBEND

想要的如下所示

<SUBBEGIN
        IMSI=XXXXXXXX;
        MSISDN=XXXXXXXXXXXX;
        DEFCALL=TS11;
        CURRENTNAM=BOTH;
        CAT=COMMON;
        TBS=TS11&TS12&TS21&TS22&TS61&BS26&BS2G;
        ODBIC=BAIC;
        ODBOC=BAOC;
<SUBEND

请大家推荐一下!!

答案1

使用 GNU awk

gawk -v 'RS=<SUBEND\n' -v ORS= -F'\n' '
  NF > max {max = NF; ret = $0 RT}
  END      {if (max) print ret}'

这里我们将<SUBEND换行符设置为RecordS分隔符。因此,记录将从一个运行<SUBEND\n到下一个,这在您的示例输入中确实匹配<SUBBEGIN...<SUBEND记录。如果这些记录之间可能存在其他内容,或者一个记录与下一个记录<SUBBEGIN...<SUBEND之间可能没有换行符,则必须调整该方法。<SUBEND<SUBBEGIN

例如:

gawk -v 'RS=<SUBEND' -F'\n' '
  !(RT && sub(/.*<SUBBEGIN/, "<SUBBEGIN")) {next}
  NF > max {max = NF; ret = $0 RT}
  END      {if (max) print ret}'

答案2

使用awk

awk '
  {lines[NR]=$0}
  $0 == "<SUBBEGIN" {start=NR}
  $0 == "<SUBEND" && (NR-start) > subsize {substart=start; subsize=(NR-start)} 
  END{for (i=substart; i<=(substart+subsize);i++) print lines[i]}
' file
  • {lines[NR]=$0}- 将所有行保存到数组中
  • $0 == "<SUBBEGIN" {start=NR}在“sub”开始时保存行号
  • $0 == "<SUBEND" && (NR-start) > subsize {substart=start; subsize=(NR-start)}当“sub”结束并且是迄今为止最长的“sub”时,保存 substart变量subsize
  • END{for (i=substart; i<=(substart+subsize);i++) print lines[i]}- 从保存的数组中,打印subsize行,从substart

答案3

尝试将此作为起点:

awk '
/<SUBBEGIN/     {NRBEGIN   = NR
                 IMSIFOUND = 0
                }
/<SUBEND/       {if (IMSIFOUND) {DELTA = NR - NRBEGIN
                                 if (DELTA > DLMX)      {DLMX = DELTA
                                                         NRMX = NRBEGIN
                                                        }
                                }
                }
/IMSI/          {IMSIFOUND = 1
                }
END             {print NRMX ",+" DLMX "p"
                }
' file |  sed -nf- file
        IMSI=XXXXXXXX;
        MSISDN=XXXXXXXXXXXX;
        DEFCALL=TS11;
        CURRENTNAM=BOTH;
        CAT=COMMON;
        TBS=TS11&TS12&TS21&TS22&TS61&BS26&BS2G;
        ODBIC=BAIC;
        ODBOC=BAOC;
<SUBEND

如果在两者之间找到“IMSI”,它会记录最大块的起始行号和结束行号,并在该END部分中打印一个小sed脚本,该脚本打印出相应的行。

如果您不想使用两个不同的命令运行大文件两次,请尝试

awk '
/<SUBBEGIN/     {delete WIP
                 CNT = IMSIFOUND = 0
                }
                {WIP[++CNT] = $0
                }
/<SUBEND/       {if (IMSIFOUND) {if (CNT > MAX) {for (i=1; i<=CNT; i++) BLOCK[i] = WIP[i]
                                                 MAX   = CNT
                                                }
                                }
                }
/IMSI/          {IMSIFOUND = 1
                }
END             {for (i=1; i<=MAX; i++) print BLOCK[i]
                }
' file5
<SUBBEGIN
        IMSI=XXXXXXXX;
        MSISDN=XXXXXXXXXXXX;
        DEFCALL=TS11;
        CURRENTNAM=BOTH;
        CAT=COMMON;
        TBS=TS11&TS12&TS21&TS22&TS61&BS26&BS2G;
        ODBIC=BAIC;
        ODBOC=BAOC;
<SUBEND

答案4

我们可以使用 来做到这一点sed,这里显示的是扩展正则表达式模式下的 GNU sed (-E)

B='<SUBBEGIN'
E='<SUBEND'

sed -E "/\n/q
  /^$B\$/!d
  s/^/\n/
  :loop
    N;s/^/_/
  /\n$E\$/!bloop
  G;ta;:a
  /^(_+)(\n$B\n).*\n\1_+\2/!s/(\n$E)\n.*/\1/
  tupdt
  g;:updt
  h;\$D;d
" file

方案如下:

  • 对于读取的每一行,在开头放置一个下划线。
  • 我们将比较块开始后面的前导下划线的长度。
  • 在模式空间中累积块。
  • 将保留粘贴到图案空间上。
  • 仅当模式空间块下划线比hold更长或相同时,我们才会将新块存储在hold中。

相关内容