使用sed命令反向引用获非预期结果,求原因及优化方法
sed反向引用问题分析与格式调整
原始文件内容:
abab102 cdcd103 efef105
需求:将每行的4位字母(用户名)和3位数字(ID)分离,格式化为Username:xxx ID:xxx。
第一个命令的问题
执行以下命令后结果不符合预期:
sed 's/\([a-z]\)\{4\}\([0-9]\)\{3\}/Username:\1 ID:\2/' file.txt
得到的结果:
Username:b ID:2 Username:d ID:3 Username:f ID:5
原因是基础POSIX sed中,分组\([a-z]\)仅捕获单个字符,后面的\{4\}是重复匹配这个分组4次,但分组只会保留最后一次匹配的内容。同理\([0-9]\)\{3\}也只保留最后一个数字,所以\1取的是第4个字母,\2取的是第3个数字,导致结果错误。
正确的写法应该把整个重复的匹配内容放进分组,也就是让括号包裹住整个重复单元:
sed 's/\([a-z]\{4\}\)\([0-9]\{3\}\)/Username:\1 ID:\2/' file.txt
这样\([a-z]\{4\}\)会捕获全部4个字母,\([0-9]\{3\}\)捕获全部3个数字,执行后就能得到预期结果:
Username:abab ID:102 Username:cdcd ID:103 Username:efef ID:105
如果使用扩展正则表达式(加-r参数,无需转义括号和量词),写法更简洁:
sed -r 's/([a-z]{4})([0-9]{3})/Username:\1 ID:\2/' file.txt
第二个命令的空格问题
执行以下命令后,用户名和ID之间缺少空格:
sed -e 's/\([a-z]\)\{4\}/Username:&/' -e 's/\([0-9]\)\{3\}/ID:&/' file2.txt
得到的结果:
Username:ababID:102 Username:cdcdID:103 Username:efefID:105
这里的&代表匹配到的整个内容,解决空格问题很简单,只要在第一个替换的末尾加空格,或者在第二个替换的ID前加空格:
# 方法1:在第一个替换的用户名后加空格 sed -e 's/\([a-z]\{4\}\)/Username:& /' -e 's/\([0-9]\{3\}\)/ID:&/' file.txt # 方法2:在第二个替换的ID前加空格 sed -e 's/\([a-z]\{4\}\)/Username:&/' -e 's/\([0-9]\{3\}\)/ ID:&/' file.txt
执行后就能得到带空格的正确格式。
内容的提问来源于stack exchange,提问作者user5499810
相关产品推荐
相关产品推荐

