为何带g标志的Sed命令仅返回一行中第二个匹配的号码?
问题分析与解决方案
原命令失效原因
你的sed命令只提取到第二个号码,核心问题在于贪婪匹配和g标志的作用场景错误:
.*是贪婪匹配,会从行首一直匹配到最后一个符合49 三位数字 七位数字格式的号码的前一个字符,此时(...)捕获的是最后一个号码,.*再匹配该号码后的所有内容,最终整个行被替换成这个唯一的捕获结果。g标志的作用是在同一行内多次替换非重叠的匹配内容,但你的命令是把整个行替换为单个捕获值,替换完成后行内已无剩余内容可匹配,所以g完全不起作用。
纯Sed解决方案
方案1:循环捕获并打印(推荐,纯Sed实现)
sed -nE ':loop s/(.*)(49 [0-9]{3} [0-9]{7})/\1/ h s/.*(49 [0-9]{3} [0-9]{7})/\1/p g t loop' infile.in > outfile3.dat
单行简化版本:
sed -nE ':loop; s/(.*)(49 [0-9]{3} [0-9]{7})/\1/; h; s/.*(49 [0-9]{3} [0-9]{7})/\1/p; g; t loop' infile.in > outfile3.dat
原理:
:loop定义循环标签,用于重复处理剩余内容s/(.*)(49 ...)/\1/:移除行内最后一个匹配的号码,将剩余内容保留在模式空间h:把模式空间的内容(已移除一个号码的行)存入保持空间暂存s/.*(49 ...)/\1/p:回到原行内容,捕获并打印最后一个匹配的号码g:将保持空间的内容(剩余行)放回模式空间t loop:如果上一步替换成功(说明还有未提取的号码),跳转回loop标签继续处理
方案2:拆分匹配内容为独立行
sed -nE 's/.*?(49 [0-9]{3} [0-9]{7})/\n\1/g; s/^\n//; s/[^0-9 ]+\n//g; p' infile.in > outfile3.dat
原理:
s/.*?(49 ...)/\n\1/g:用非贪婪的.*?匹配到每个号码的前置内容,替换为换行+号码,全局替换后所有号码被换行分隔s/^\n//:移除行首多余的换行s/[^0-9 ]+\n//g:过滤掉非号码的无效行p:打印处理后的所有有效号码行
内容的提问来源于stack exchange,提问作者dwhite
相关产品推荐
相关产品推荐

