sed非贪婪匹配删除行首前缀命令失效原因排查
问题背景
现有待处理文本如下:
1a.begin /path/1a.file 2bx.begin2 /path/my/2bx.file2
期望处理后输出:
begin /path/1a.file begin2 /path/my/2bx.file2
已知sed默认采用贪婪匹配规则,若直接使用贪婪匹配规则会将行内所有的1a.和2bx.内容都移除,不符合预期,因此尝试通过sed非贪婪匹配实现需求,执行的命令如下:
echo -e "1a.begin /path/1a.file\n2bx.begin2 /path/my/2bx.file2"|sed 's/$.*[^\.]\.//g'
编写该命令时的原本意图是:用$.*匹配从行首起始的所有字符串,用[^\.]避免贪婪匹配到行内所有的.,参考了sed非贪婪匹配的相关实现方案,但执行后文本没有发生任何替换,需要排查脚本错误。
错误排查
你写的sed替换正则存在两个核心问题:
- 行锚点符号使用完全错误
正则中$是行尾锚点,作用是匹配一行的结束位置,你想要匹配行首应该使用^符号。你写的$.*逻辑是「先定位到行尾,再匹配行尾之后的任意长度任意字符」,行尾之后不存在任何字符,因此整个正则永远无法匹配到内容,自然不会触发替换。 - 非贪婪匹配的实现逻辑错误
就算把$修正为^,^.*[^\.]\.的写法也达不到预期效果:.*本身是贪婪匹配,会优先吞掉整行内容,再回溯查找满足「非.字符 +.」的位置,最终会定位到整行最后一个.的位置,替换后只会剩下最后一个.后面的内容,比如第一行最终只会输出file,和预期效果完全不符。
正确实现方案
sed基础正则本身不支持非贪婪量词,不需要硬凑非贪婪写法,直接精准匹配「行首到第一个.的所有内容(包含第一个.)」,将其替换为空即可,命令如下:
echo -e "1a.begin /path/1a.file\n2bx.begin2 /path/my/2bx.file2" | sed 's/^[^.]*\.//'
正则逻辑说明:
^:匹配行首位置[^.]*:匹配连续任意个非.的字符,正好对应开头的1a、2bx这类前缀\.:匹配前缀后紧跟的第一个.
整个匹配只会命中每行开头到第一个.的部分,完全不会影响后续路径中出现的1a.、2bx.内容,执行后正好得到预期输出。
内容的提问来源于stack exchange,提问作者user13846961
相关产品推荐
相关产品推荐

