shell中sed学习之替换 \1 \2 \3的几点谜思
来源:互联网 发布:淘宝10元包邮网址 编辑:程序博客网 时间:2024/06/05 18:35
今天在学习shell时,无意中碰到了这样一个脚本,其中有行用到了sed
echo “111(222)333" | sed 's/(\(.*\))(.*)/\2\2\2/'看完后,百思不得其解,因为本人目前只是对shell略懂皮毛,只知道基本的语法格式。然后就百度,终于明白了这是怎么一回事。
按上面这个例子,在sed替换语句那里,有两个表达式,(\(.*\)) 和 ( .* ),其中前一个有时有转义符,有时没有,表示,有转义符时,表示正则表达式 POSIX 的基本正则表达式 ( BER )引擎的字符组,表示里面的内容会出现,如果里面有多个内容,则至少会出现一个,这里,里面是 .*,点通配符 . 表示可以匹配除换行符之外的任意单个字符,而 * 表示可以出现任意多次,包括依次都不出现。
而前面没加转义符的一队双括号其实可以理解为一个标志,因为 echo 后面的语句有一对双括号,这是 sed 后的语句的双括号正好与之配对。所以,sed 后的替换语句中, ( \( .*\))表示的就是(222),而着后面的 (. *) 就是表示(222) 厚的所有内容。而后面的 \2表示的是这两个部分的第二个部分,即 (.*), 这里用到了三个 \2, 则会将这个部分重复三次,而前面的部分 111 没有影响,会直接输出,所以整个输出就是:
111333333333。
如果此处将 \2 改为 \1, 则会将 222 重复出现三次, 结果为 111222222222。
当然,echo 语句中的括号我可以换成别的,如 111y222y333,那么,要得到相同的输出,则应该这么改写语句:
echo "111y222y333" | sed 's/y\(.*\)y(.*)/\2\2\2/'
两个括号及其以上得情况:
[root@mail root]# echo "no1=100(AAA) no2=100(BBB) no3=100(CCC)no4=(DDD)" | sed 's/\(.*\)(\(.*\)).*/\2/'
DDD
[root@mail root]# echo "no1=100(AAA) no2=100(BBB) no3=100(CCC)no4=(DDD)" | sed 's/.*(\(.*\)).*/\1/'
DDD
以上两句意义相同。
我们本想取到AAA,但是为什么取了DDD呢
正则表达式是有贪婪性的,它总是与最长的可能长度匹配,而且越是排在前面的通配符优先级越高。按照这样的原则取到得就是DDD了,那么我们应该如何取得AAA呢?
我们考虑如果在模式串中第一个.*中告诉sed这个.*是不能含有"("的,同时第二个.*中不能含有")"应该OK吧
试一试:
[root@mail root]# echo "no1=100(AAA) no2=100(BBB) no3=100(CCC)no4=(DDD)" | sed 's/[^(]*(\([^)]*\)).*/\1/'
AAA
以此类推,可以得到
[root@mail root]# echo "no1=100(AAA) no2=100(BBB) no3=100(CCC)no4=(DDD)" | sed's/[^(]*(\([^)]*\))[^(]*(\([^)]*\))[^(]*(\([^)]*\))[^(]*(\([^)
]*\))/\2/'
BBB
将2改为3就是CCC
将3改为4就是DDD
上面这段是博客 点击打开链接,因为以目前所学的水平,还体会不了这段的意思,特摘来提醒自己,要继续学习,勤于思考,争取早日将这个问题弄懂。
以上文章是写于2014-09-20 10:18,当时没弄懂上面一个问题,现在经过继续的学习,终于搞明白了。
还是用上面 echo 语句输出的字串,当我本来想用 sed 输出 AAA 时,却还是输出 DDD。这是由于正则表达式的贪婪性。正如上面说的,正则表达式总是与最长的可能长度匹配,而且越是排在前面的通配符优先级越高,我们来看 sed语句:
sed 's/.*(\(.*\))/\1/'第一个通配符 .* 优先级较第二个高,它会匹配可能的最大长度,即匹配字串 ”no1=100(AAA) no2=100(BBB) no3=100(CCC)no4= “,所以当你输出 括号内匹配的第一个内容时,就会输出 DDD。怎么解决这个问题呢?请看下面分解:
由于贪婪行,使得输出结果有误。让我们仔细看上面那个字串,不是有四个括号吗!我要输出 AAA,即是输出第一个括号的内容,所以只要我能匹配到第一个括号,那不就完美的解决了这个问题吗。实际上,也就是如此。
那么,怎么来匹配第一个括号呢?
看字串里,要想匹配括号内的数据,会用正则表达式 (\(.*\)),要想第一个呢?那么,我们只要在匹配括号内的内容时,让它前面不要出现 左双括号 “(” 不就可以了吗!所以,问题的关键就在这里。我们可以用下面的正则表达式来达到这一目的:
sed 's/[^(]*(\(.*\)).*/\1/'
这样,输出就可以得到 AAA 了。
那么,如果我想得到 BBB ,CCC,怎么办呢?
这个问题就留给读者来回答吧!
- shell中sed学习之替换 \1 \2 \3的几点谜思
- 在shell中调用sed中替换斜杠的问题
- 在shell中调用sed中替换斜杠的问题
- shell中使用sed替换指定位置的字符
- shell学习之sed
- Shell sed 替换操作
- Shell脚本的学习&&sed
- sed的使用1-替换
- shell中sed的使用
- shell中sed的使用
- shell学习第十天----sed查找与替换
- shell学习第十天----sed查找与替换
- shell脚本之sed使用----替换、变量、转义字符
- 【shell】sed学习小结1
- shell sed 实现文本替换
- shell学习之-sed用法解析
- shell学习之-sed用法解析
- shell学习之-sed用法解析
- JS页面跳转整理
- CF #12 D Ball
- Python基础教程(第六章)
- 【高效会议】纠音活动低效的解决办法
- java操作Oracle
- shell中sed学习之替换 \1 \2 \3的几点谜思
- 基于标签的推荐系统学习(1)
- 有关实习、毕业论文及软件开发和测试的关系等问题
- PAT 1008. 数组元素循环右移问题
- MODBUS RTU通信校验码的代码:
- innerHTML、innerText和outerHTML、outerText的区别
- Eclipse Maven install build 无任何作用
- hdu 5019 Revenge of GCD(BestCoder Round #10)
- android 创建工程的 package-info.java