免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3355 | 回复: 11

[文本处理] grep求助 [复制链接]

论坛徽章:
0
发表于 2015-12-08 17:40 |显示全部楼层
今天得到一个日志文件要处理一下,内容如下:
  1. $ cat test
  2. 1449563551|Fun1|0|Fun2|0|
  3. 1449563552|Fun1|0|Fun2|0|
  4. 1449563553|Fun1|0|Fun2|0|
  5. 1449563554|Fun1|0|Fun2|10001|
  6. 1449563555|Fun1|10002|Fun2|10002|
  7. |0test line|
复制代码
最后一行是我加上去测试用的,主要目的是抽取其中状态标识 |0| <= 1的行,首先测试基本的grep功能:
  1. $ grep '|0|' test
  2. 1449563551|Fun1|0|Fun2|0|
  3. 1449563552|Fun1|0|Fun2|0|
  4. 1449563553|Fun1|0|Fun2|0|
  5. 1449563554|Fun1|0|Fun2|10001|

  6. $ grep "|0|" test
  7. 1449563551|Fun1|0|Fun2|0|
  8. 1449563552|Fun1|0|Fun2|0|
  9. 1449563553|Fun1|0|Fun2|0|
  10. 1449563554|Fun1|0|Fun2|10001|
复制代码
可以看到这里不加转义(‘\|0\)’)是可以使用的,而用了转义反而不行:
  1. $ grep '\|0\|' test
  2. 1449563551|Fun1|0|Fun2|0|
  3. 1449563552|Fun1|0|Fun2|0|
  4. 1449563553|Fun1|0|Fun2|0|
  5. 1449563554|Fun1|0|Fun2|10001|
  6. 1449563555|Fun1|10002|Fun2|10002|
  7. |0test line|
复制代码
在试一下指定匹配数量,也不能工作(我觉得最后一行不应该出现):
  1. $ grep '|0|\{1\}' test
  2. 1449563551|Fun1|0|Fun2|0|
  3. 1449563552|Fun1|0|Fun2|0|
  4. 1449563553|Fun1|0|Fun2|0|
  5. 1449563554|Fun1|0|Fun2|10001|
复制代码
困惑啊,有大大解释一下吗,怎么才能正确的匹配 |0| <= 1的行呢

论坛徽章:
766
金牛座
日期:2014-02-26 17:49:58水瓶座
日期:2014-02-26 18:10:15白羊座
日期:2014-04-15 19:29:52寅虎
日期:2014-04-17 19:43:21酉鸡
日期:2014-04-19 21:24:10子鼠
日期:2014-04-22 13:55:24卯兔
日期:2014-04-22 14:20:58亥猪
日期:2014-04-22 16:13:09狮子座
日期:2014-05-05 22:31:17摩羯座
日期:2014-05-06 10:32:53处女座
日期:2014-05-12 09:23:11子鼠
日期:2014-05-21 18:21:27
发表于 2015-12-08 17:46 |显示全部楼层
回复 1# ForCalm

一定要grep, awk不可以吗?
   

论坛徽章:
50
15-16赛季CBA联赛之广夏
日期:2018-11-05 09:42:462015年亚冠纪念徽章
日期:2015-07-23 11:58:122015亚冠之广州富力
日期:2015-07-07 08:26:172015亚冠之塔什干棉农
日期:2015-06-29 09:08:072015年亚洲杯之伊朗
日期:2015-03-08 20:51:012015年迎新春徽章
日期:2015-03-04 09:58:11未羊
日期:2014-10-16 22:41:47处女座
日期:2014-10-16 15:33:33酉鸡
日期:2014-03-13 12:54:10巳蛇
日期:2014-03-10 14:39:052015亚冠之德黑兰石油
日期:2015-07-29 12:46:372015亚冠之德黑兰石油
日期:2015-08-07 12:54:11
发表于 2015-12-08 17:50 |显示全部楼层
  1. grep '|0|$'
复制代码

论坛徽章:
39
辰龙
日期:2013-08-21 15:45:192015亚冠之广州富力
日期:2015-05-12 16:34:52亥猪
日期:2015-03-03 17:22:00申猴
日期:2015-03-03 17:21:37未羊
日期:2014-10-10 13:45:41戌狗
日期:2014-06-17 09:53:29巨蟹座
日期:2014-06-12 23:17:17双鱼座
日期:2014-06-10 12:42:44寅虎
日期:2014-06-09 12:52:172015亚冠之卡尔希纳萨夫
日期:2015-05-24 15:24:35黄金圣斗士
日期:2015-12-02 17:25:0815-16赛季CBA联赛之吉林
日期:2017-06-24 16:43:52
发表于 2015-12-08 17:56 |显示全部楼层
本帖最后由 关阴月飞 于 2015-12-08 17:57 编辑

用awk吧,是这意思不:
  1. [root@test ~]# cat a
  2. 1449563551|Fun1|0|Fun2|0|
  3. 1449563552|Fun1|0|Fun2|0|
  4. 1449563553|Fun1|0|Fun2|0|
  5. 1449563554|Fun1|0|Fun2|10001|
  6. 1449563555|Fun1|10002|Fun2|10002|
  7. |0test line|
  8. [root@test ~]# awk -F'\\|0\\|' 'NF<=2' a
  9. 1449563554|Fun1|0|Fun2|10001|
  10. 1449563555|Fun1|10002|Fun2|10002|
  11. |0test line|
复制代码

论坛徽章:
0
发表于 2015-12-08 21:03 |显示全部楼层
回复 2# Herowinter


    awk肯定是可以的,但是我觉得grep会简单一点,所以初始想法就落在了grep上

论坛徽章:
0
发表于 2015-12-08 21:06 |显示全部楼层
回复 4# 关阴月飞


    谢谢,效果是好的,但是兼容性差点,如果新增加一个Fun,就得改脚本。其实最终目的很简单,每一行至少会有一个Fun和它的状态码,如果发现一行中有状态码不是|0|,则将其滤出。

论坛徽章:
766
金牛座
日期:2014-02-26 17:49:58水瓶座
日期:2014-02-26 18:10:15白羊座
日期:2014-04-15 19:29:52寅虎
日期:2014-04-17 19:43:21酉鸡
日期:2014-04-19 21:24:10子鼠
日期:2014-04-22 13:55:24卯兔
日期:2014-04-22 14:20:58亥猪
日期:2014-04-22 16:13:09狮子座
日期:2014-05-05 22:31:17摩羯座
日期:2014-05-06 10:32:53处女座
日期:2014-05-12 09:23:11子鼠
日期:2014-05-21 18:21:27
发表于 2015-12-08 21:42 |显示全部楼层
本帖最后由 Herowinter 于 2015-12-08 21:45 编辑

回复 6# ForCalm

你要的效果是这个吗?
grep -P '^[0-9]+((?!\|[1-9][0-9]*\|).)*$' test.txt
1449563551|Fun1|0|Fun2|0|
1449563552|Fun1|0|Fun2|0|
1449563553|Fun1|0|Fun2|0|

cat test.txt
1449563551|Fun1|0|Fun2|0|
1449563552|Fun1|0|Fun2|0|
1449563553|Fun1|0|Fun2|0|
1449563554|Fun1|0|Fun2|10001|
1449563555|Fun1|10002|Fun2|10002|
|0test line|

论坛徽章:
0
发表于 2015-12-08 21:52 |显示全部楼层
本帖最后由 ForCalm 于 2015-12-08 21:59 编辑

回复 7# Herowinter


    结果是对的,只要取反就是希望的内容,但我在本地执行结果有点差异,是不是我理解错了?
  1. $ grep -P '^[0-9]+((?!\|[1-9][0-9]*\|).)*' test
  2. 1449563551|Fun1|0|Fun2|0|
  3. 1449563552|Fun1|0|Fun2|0|
  4. 1449563553|Fun1|0|Fun2|0|
  5. 1449563554|Fun1|0|Fun2|10001|
  6. 1449563555|Fun1|10002|Fun2|10002|
复制代码
现在最让我疑惑的已经不是取内容了,而是怎么让grep支持‘|0|’,也就是如何能匹配这个模式并设置匹配次数。

论坛徽章:
766
金牛座
日期:2014-02-26 17:49:58水瓶座
日期:2014-02-26 18:10:15白羊座
日期:2014-04-15 19:29:52寅虎
日期:2014-04-17 19:43:21酉鸡
日期:2014-04-19 21:24:10子鼠
日期:2014-04-22 13:55:24卯兔
日期:2014-04-22 14:20:58亥猪
日期:2014-04-22 16:13:09狮子座
日期:2014-05-05 22:31:17摩羯座
日期:2014-05-06 10:32:53处女座
日期:2014-05-12 09:23:11子鼠
日期:2014-05-21 18:21:27
发表于 2015-12-08 22:23 |显示全部楼层
本帖最后由 Herowinter 于 2015-12-08 22:31 编辑

回复 8# ForCalm

我看懂你的需求了,应该是这样。

grep -P '^((?!\|0\|).)*(\|0\|)?((?!\|0\|).)*$' test.txt
1449563554|Fun1|0|Fun2|10001|
1449563555|Fun1|10002|Fun2|10002|
|0test line|


上面的代码分成这两个正则容易理解点,包含了从行首开始后面
没有“\|0\|”和只有1个”\|0\|“的两种情况。

grep -P '^((?!\|0\|).)*$' test.txt
1449563555|Fun1|10002|Fun2|10002|
|0test line|

grep -P '^((?!\|0\|).)*\|0\|((?!\|0\|).)*$' test.txt
1449563554|Fun1|0|Fun2|10001|


   

论坛徽章:
0
发表于 2015-12-08 23:08 |显示全部楼层
回复 9# Herowinter


    非常感谢,我发现自己之前对re好像犯了概念性的错误,你的思路应该才是对的,明天再去细细研究下代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP