忘记密码   免费注册 查看新帖 | 论坛精华区

ChinaUnix.net

  平台 论坛 博客 认证专区 大话IT 视频 徽章 文库 沙龙 自测 下载 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
查看: 51862 | 回复: 103

【5楼解答的很详细,大家可以讨论下】sed 地址和模式匹配的问题 [复制链接]

论坛徽章:
0
发表于 2011-06-25 09:25 |显示全部楼层
本帖最后由 expert1 于 2011-07-22 13:59 编辑

[root@oracle tmp]# cat e_test.txt
1
2
3
4
5
6
[root@oracle tmp]# sed -e '1,2d' -e '1,2d' e_test.txt
4
5
6
[root@oracle tmp]# sed  '1,2d' e_test.txt |sed  '1,2d'
5
6


这两个命令为啥结果不一样,-e怎么执行的?

第一个命令执行的没有   3

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:51:162015年亚洲杯之阿曼
日期:2015-04-07 20:00:59
发表于 2011-06-25 10:13 |显示全部楼层
  1. PATT:1$
  2. HOLD:$
  3. COMM:1,2 d
  4. PATT:2$
  5. HOLD:$
  6. COMM:1,2 d
  7. PATT:3$
  8. HOLD:$
  9. COMM:1,2 d
  10. PATT:3$
  11. HOLD:$
  12. COMM:1,2 d
  13. PATT:4$
  14. HOLD:$
  15. COMM:1,2 d
  16. PATT:4$
  17. HOLD:$
  18. COMM:1,2 d
  19. PATT:4$
  20. HOLD:$
  21. 4
  22. PATT:5$
  23. HOLD:$
  24. COMM:1,2 d
  25. PATT:5$
  26. HOLD:$
  27. COMM:1,2 d
  28. PATT:5$
  29. HOLD:$
  30. 5
  31. PATT:6$
  32. HOLD:$
  33. COMM:1,2 d
  34. PATT:6$
  35. HOLD:$
  36. COMM:1,2 d
  37. PATT:6$
  38. HOLD:$
  39. 6
复制代码

论坛徽章:
0
发表于 2011-06-25 10:50 |显示全部楼层
zooyo 发表于 2011-06-25 10:13



    看不懂,另外这个是咋跟踪出来的?

论坛徽章:
0
发表于 2011-06-25 11:26 |显示全部楼层
回复 3# Nalternative


    sedsed: http://sedsed.sourceforge.net/

论坛徽章:
2
射手座
日期:2014-10-10 15:59:4715-16赛季CBA联赛之上海
日期:2016-03-03 10:27:14
发表于 2011-06-25 14:57 |显示全部楼层
本帖最后由 yinyuemi 于 2011-06-25 14:59 编辑

回复 1# Nalternative


    这个问题很有趣,所以研究下,下面是我的理解,如果有不对的地方,请大家指正

首先我觉得两段代码执行结果不同,原因比较简单,第二个代码因为使用了管道,所以相当于两个sed程序独立完成对文本的处理,第一个虽然使用了-e,但始终是在一个sed里完成的,这里我主要想说下为什么第一个代码会得出lz那样的输出结果。
(最初,我的觉得输出结果应该是

  1. 3
  2. 4
  3. 5
  4. 6
复制代码
,为什么3没有了呢?)

经过多次尝试,变化代码,最后发现问题的关键是第二个1,2这个匹配上,
sed -e '1,2d' -e '1,2d'
中的第一个1,2匹配没有问题,将第1和2行删除,
当执行到第二个1,2匹配的时候,由于第1和2行已经被删除,所以此时读入patten的行号为3,那么“1 ” 匹配是失败的,怎么还会把第三3行的数据删除呢?
原来是和line1,line2或/pattern/,line(line,/pattern/)这样的匹配模式有关,
1, 如果line和pattern匹配成功时,sed从line1匹配,直到line2或/pattern/

  1. seq 6 |sed -n '1,3p'
  2. 1
  3. 2
  4. 3
复制代码
2, 如果匹配不成功时,又有下面几种情况:
<a>, line=0时,只能使用0,/pattern/的模式,即从头匹配,直到pattern

  1. seq 6 |sed -n '0,/3/p'
  2. 1
  3. 2
  4. 3
复制代码
但下面的模式不能使用

  1. seq 6 |sed -n '0,3p'
  2. sed: -e expression #1, char 4: invalid usage of line address 0
复制代码
关于0,/pattern/的原文解释:
A line number of 0 can be used in an address specification like 0,/regexp/ so that sed will try to match regexp in the first input line too. In other words, 0,/regexp/ is similar to 1,/regexp/, except that if addr2 matches the very first line of input the 0,/regexp/ form will consider it to end the range, whereas the 1,/regexp/ form will match the beginning of its range and hence make the range span up to the second occurrence of the regular expression.

<b>, line 匹配成功,/pattern/匹配不成功,则是,从line行到最后一行

  1. seq 6 |sed -n '3,/v/p'
  2. 3
  3. 4
  4. 5
  5. 6
复制代码
<c> 就是lz举的例子中第二个line1,line2的特殊匹配情况,下面我把具体执行过程写下,
  1. seq 6 |sed -e '1,2'd -e '1,2'd
  2. 读入第一行,1,2匹配成功,执行d,删除第一行,
  3. 读入第二行,1,2匹配成功,执行d,删除第一行
  4. (这时,第一个-experssion执行完毕,执行第二个-experssion)
  5. 读入第三行,1,2匹配成功了一半,因为1匹配成功,这里可以像<a>中0一样,"try to match regexp in the first input line too",所以执行d,删除第三行。
  6. 读入第四行,1,2匹配失败,第二个experssion执行结束,
  7. 读入第五行,第六行,结束。
复制代码
为了更好的理解,结合前面<b>的情况,执行下面代码:

  1. line1=2
  2. seq 6|sed -e '1,3d' -e"$line1,3d"
  3. 5
  4. 6
  5. #看来只要line1小于当前读入的行号就判读成功,你可以试试line1等于3的情况
  6. seq 6 |sed -e '1,2d' -e"$line1,/v/d'
  7. #没有输入,因为/v/匹配失败,所以命令d会一直执行到最后一行,把所有行都被删除。
  8. seq 6 |sed -e '1,2d' -e"$line1,5d'
  9. 6
  10. #命令d只执行到第5行
复制代码
非常感谢lz的例子,让我对sed的模式匹配加深了理解
最后再show两个和sed用法很类似的awk例子,呵呵

  1. seq 6 |awk '!i++,/3/'
  2. 1
  3. 2
  4. 3

  5. seq 6 |awk '/3/,0'
  6. 3
  7. 4
  8. 5
  9. 6
复制代码
你看懂了么?

评分

参与人数 1可用积分 +10 收起 理由
xiaopan3322 + 10 好!!!

查看全部评分

论坛徽章:
0
发表于 2011-06-25 15:12 |显示全部楼层
回复  Nalternative


    这个问题很有趣,所以研究下,下面是我的理解,如果有不对的地方,请大家指正 ...
yinyuemi 发表于 2011-06-25 14:57



    非常感谢!解答的这么详细,不明白都不行了!

论坛徽章:
10
天蝎座
日期:2013-09-22 22:32:23程序设计版块每日发帖之星
日期:2016-08-07 06:20:00lufei
日期:2016-06-17 17:38:40程序设计版块每日发帖之星
日期:2016-06-12 06:20:002016科比退役纪念章
日期:2016-05-31 15:47:20CU十四周年纪念徽章
日期:2016-05-27 12:24:562015年亚洲杯之阿曼
日期:2015-05-03 21:01:352015年辞旧岁徽章
日期:2015-03-03 16:54:15天蝎座
日期:2013-10-20 21:05:24程序设计版块每日发帖之星
日期:2016-08-11 06:20:00
发表于 2011-06-25 16:21 |显示全部楼层
学习

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:51:162015年亚洲杯之阿曼
日期:2015-04-07 20:00:59
发表于 2011-06-25 17:20 |显示全部楼层
只有膜拜了。

论坛徽章:
1
双子座
日期:2013-10-17 00:46:45
发表于 2011-06-26 01:09 |显示全部楼层
佩服 yinyuemi (SS) 兄的学习与分享精神~

论坛徽章:
1
双子座
日期:2013-10-17 00:46:45
发表于 2011-06-26 01:40 |显示全部楼层
回复 5# yinyuemi

这里的”1,2匹配成功了一半,因为1匹配成功,“我看的不太明白:
1匹配成功了?前面的1,2d不是已经把1,2都删掉了嘛~ 后面的1和2都应该是匹配失败的啊?麻烦 yinyuemi 帮忙解释下~ 谢谢~
   
    seq 6 |sed -e '1,2'd -e '1,2'd
    读入第一行,1,2匹配成功,执行d,删除第一行,
    读入第二行,1,2匹配成功,执行d,删除第一行
    (这时,第一个-experssion执行完毕,执行第二个-experssion)
    读入第三行,1,2匹配成功了一半,因为1匹配成功,这里可以像<a>中0一样,"try to match regexp in the first input line too",所以执行d,删除第三行。
    读入第四行,1,2匹配失败,第二个experssion执行结束,
    读入第五行,第六行,结束。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

  

北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:1101082001
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP