如何筛选blockBEGIN与blockEND间含指定正则模式的文本块?
问题描述
我尝试用sed+grep组合筛选包含指定正则模式的文本块,设置了以下变量和命令:
$ blockBEGIN='ID' $ blockEND='Sector Size' $ myPATTERN='Ready' $ cat pdisks-simplified-20230825.log | sed -n "/$blockBEGIN/,/$blockEND/{/$blockEND/"'s/$/\x00/;p}' | grep -z "$myPATTERN" | grep -z -v "$blockEND" | tr -d '\x00'
但执行后没有任何输出。
示例输入日志:
ID : 0:1:4 Status : Ok State : Ready Power Status : Spun Up Bus Protocol : SAS Media : HDD Capacity : 3,725.50 GB (4000225165312 bytes) Vendor ID : DELL(tm) Product ID : ST4000NM0023 Serial No. : Z1Z6AAR9 Part Number : TH0529FG212334AI01AGA02 Sector Size : 512B ID : 0:1:0 Status : Ok State : Online Power Status : Not Applicable Bus Protocol : SATA Media : SSD Capacity : 372.00 GB (399431958528 bytes) Vendor ID : DELL(tm) Product ID : INTEL SSDSC2BX400G4R Serial No. : BTHC721403F8400VGN Part Number : CN065WJJIT200766014OA00 Sector Size : 512B
需要筛选出的符合条件的文本块(包含Ready):
ID : 0:1:4 Status : Ok State : Ready Power Status : Spun Up Bus Protocol : SAS Media : HDD Capacity : 3,725.50 GB (4000225165312 bytes) Vendor ID : DELL(tm) Product ID : ST4000NM0023 Serial No. : Z1Z6AAR9 Part Number : TH0529FG212334AI01AGA02 Sector Size : 512B
不符合条件的文本块(不包含Ready):
ID : 0:1:0 Status : Ok State : Online Power Status : Not Applicable Bus Protocol : SATA Media : SSD Capacity : 372.00 GB (399431958528 bytes) Vendor ID : DELL(tm) Product ID : INTEL SSDSC2BX400G4R Serial No. : BTHC721403F8400VGN Part Number : CN065WJJIT200766014OA00 Sector Size : 512B
请问该如何正确实现需求?
解决方案
原命令的问题出在grep -z -v "$blockEND"这一步:它会把包含Sector Size的内容全部过滤掉,但每个目标块的结尾恰好是Sector Size行,导致最终无输出。
以下是两种可行的修复方案:
方法1:纯sed实现(推荐)
直接用sed完成块定位+模式筛选逻辑,无需额外工具:
blockBEGIN='ID' blockEND='Sector Size' myPATTERN='Ready' sed -n "/$blockBEGIN/{:a;N;/$blockEND/!ba;/$myPATTERN/p}" pdisks-simplified-20230825.log
逻辑说明:
/blockBEGIN/{...}:匹配到ID行时,执行后续逻辑:a;N;/blockEND/!ba:循环读取后续行,直到匹配到Sector Size,将整个块读入模式空间/myPATTERN/p:如果当前块包含Ready,则输出整个块
方法2:修复原sed+grep组合
保留原块分割逻辑,调整过滤和格式转换步骤:
blockBEGIN='ID' blockEND='Sector Size' myPATTERN='Ready' cat pdisks-simplified-20230825.log | sed -n "/$blockBEGIN/,/$blockEND/{/$blockEND/s/$/\x00/;p}" | grep -z "$myPATTERN" | tr '\x00' '\n'
调整点:
- 移除
grep -z -v "$blockEND",避免过滤掉块的结尾行 - 将
tr -d '\x00'改为tr '\x00' '\n',把块间的空分隔符换回换行,保证输出格式正常
内容的提问来源于Stack Exchange,提问作者SebMa
相关产品推荐
相关产品推荐

