我有一个以 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
换行符设置为R
ecordS
分隔符。因此,记录将从一个运行<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中。