LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 6574|回复: 29

[精彩讨论]sed/awk的新问题[基本解决]

[复制链接]
发表于 2004-4-9 22:32:40 | 显示全部楼层 |阅读模式
还是关于使用sed和awk。有这样的一个文件,列出其中的三列如:
----------------------------------------------------------------------------

1~906071~213435245(Apr 08 time 2004)
### EVENT ###
aksldlamalsdf
asdjalskdfjal

### END EVENT ###
PROCESSED

1~906072~458748239(Apr 08 time 2004)
### EVENT ###
kdieiejr
jkjviej

### END EVENT ###
PARSING_FAILED

1~906073~8782293(Apr 08 time 2004)
### EVENT ###
ierueio
dkjfire

### END EVENT ###
PARSING_FAILED

----------------------------------------------------------------------------------------------
这个文件的头和尾有空行, “### EVENT ###” 和“### END EVENT ###” 之间有空行。问题还是如何利用sed或awk得到这样的结果:
1. 去掉头和尾的空行。
2. 去掉“### EVENT ###” 和“### END EVENT ###”之间的那个空行。
3. 保留EVENT之间的空行。
4. 只显示带有PARSING_FAILED的EVENT。 可不是就是PARSING_FAILED的那一行,是PARSING_FAILED那整个EVENT。如:
-------------------------------------------------------------------------------------
1~906073~8782293(Apr 08 time 2004)
### EVENT ###
ierueio
dkjfire
### END EVENT ###
PARSING_FAILED

1~906072~458748239(Apr 08 time 2004)
### EVENT ###
kdieiejr
jkjviej
### END EVENT ###
PARSING_FAILED
-------------------------------------------------------------------------------------

惭愧,在下的sed/awk都不精,还请shell高手指教。谢谢!!!!!!!!!!!!!
发表于 2004-4-9 23:26:20 | 显示全部楼层
有点复杂,请楼主先试试吧。
  1. /^### EVENT ###/ {                     
  2.   x                                    
  3.   G                                    
  4.   : a                                 
  5.   N                                    
  6.   /\n### END EVENT ###/ !b a           
  7.   N                                    
  8.   /\nPARSING_FAILED/ {                 
  9.     s/\n\n/\n/g                        
  10.     N                                 
  11.     p                                 
  12.   }                                    
  13. }                                      
  14. h     
复制代码
 楼主| 发表于 2004-4-9 23:28:57 | 显示全部楼层
哇,先谢谢!!! 虽然看不懂,但先试试,等着交差呢...
 楼主| 发表于 2004-4-9 23:44:00 | 显示全部楼层
我copy了r2007兄你的code, 做成sedcmd文件, 然后’ sed -f sedcmd targetfile', 结果是这样的:
-----------------------------------------------------------------------------
1~909284~1~1081446187(Apr 08 11:43:07 2004)
1~909284~1~1081446187(Apr 08 11:43:07 2004)
### EVENT ###
werweqerq
werqerqerq
dfee
END
                                                                                                                                                                 
### END EVENT ###
PROCESSED
                                                                                                                                                                  
1~909285~1~1081446207(Apr 08 11:43:27 2004)
1~909285~1~1081446207(Apr 08 11:43:27 2004)
### EVENT ###
aswerqwef
fsdfwew
qfeq
END
                                                                                                                                                                  
### END EVENT ###
PROCESSED
                                                                                                                                                                  
1~909286~1~1081446214(Apr 08 11:43:34 2004)
1~909286~1~1081446214(Apr 08 11:43:34 2004)
### EVENT ###
wergd
fdcqae
ccasd
END
### END EVENT ###
PARSING_FAILED
------------------------------------------------------------------------------------------

PARSING_FAILED 的EVENT是都连上了,可是为什么还有其他的非PARSING_FAILED的EVENT出来呢? 时间都变成了两行了。如何才能屏蔽所以非PARSING_FAILED的EVENT, 只显示PARSING_FAILED的EVENT呢?
多谢多谢!
发表于 2004-4-9 23:50:09 | 显示全部楼层
sorry,忘了说明,要加-n参数。
  1. sed -nf sedcmd targetfile
复制代码
发表于 2004-4-9 23:58:29 | 显示全部楼层
我也给出我的awk脚本,较长。不过总觉得用awk比sed直观,而且更容易扩展。

  1. [root@home root]# cat myawk2
  2. BEGIN{
  3.         FS="\n"
  4. }
  5. {
  6.         for(i=1;i<=NF;i++){
  7.                 if($i ~ /^[0-9]/){
  8.                         valids[++cnt]=$i
  9.                         continue
  10.                 }
  11.                 if($i == "### END EVENT ###"){
  12.                         eof=1
  13.                         valids[++cnt]=$i
  14.                         continue
  15.                 }
  16.                 if(eof == 1){
  17.                         if($i == "PARSING_FAILED"){
  18.                                 for(j=1;j<=cnt;j++){
  19.                                         print valids[j]
  20.                                 }
  21.                                 print $i
  22.                                 print ""
  23.                         }
  24.                         for(j=1;j<=cnt;j++){
  25.                                 delete valids[j]
  26.                         }
  27.                         eof=0
  28.                         cnt=0
  29.                         continue
  30.                 }
  31.                 valids[++cnt]=$i
  32.         }
  33. }
  34. [root@home root]# awk -f myawk2 tmpdata
  35. 1~906072~458748239(Apr 08 time 2004)
  36. ### EVENT ###
  37. kdieiejr
  38. jkjviej
  39. ### END EVENT ###
  40. PARSING_FAILED

  41. 1~906073~8782293(Apr 08 time 2004)
  42. ### EVENT ###
  43. ierueio
  44. dkjfire
  45. ### END EVENT ###
  46. PARSING_FAILED

复制代码

有一个小bug,过滤后的文本的最后一个空行没有去掉,兄弟自己去掉吧。我这边宿舍快要断电了,呵呵。
 楼主| 发表于 2004-4-10 00:00:34 | 显示全部楼层
成了!加了n参数就只显示需要的输出了。 牛! 佩服!一定要好好研究一下r2007兄你的code。
 楼主| 发表于 2004-4-10 00:04:54 | 显示全部楼层
我也给出我的awk脚本,较长。不过总觉得用awk比sed直观,而且更容易扩展。   源码:   [root@home root]# cat myawk2 BEGIN{         FS="\n" } {         for(i=1;i<=NF;i++){                 if($i ~ /^[0-9]/){                         valids[++cnt]=$i                         continue                 }                 if($i == "### END EVENT ###"){                         eof=1                         valids[++cnt]=$i                         continue                 }                 if(eof == 1){                         if($i == "ARSING_FAILED"){                                 for(j=1;j<=cnt;j++){                                         print valids[j]                                 }                                 print $i                                 print ""                         }                         for(j=1;j<=cnt;j++){                                 delete valids[j]                         }                         eof=0                         cnt=0                         continue                 }                 valids[++cnt]=$i         } } [root@home root]# awk -f myawk2 tmpdata 1~906072~458748239(Apr 08 time 2004) ### EVENT ### kdieiejr jkjviej ### END EVENT ### PARSING_FAILED  1~906073~8782293(Apr 08 time 2004) ### EVENT ### ierueio dkjfire ### END EVENT ### PARSING_FAILED   有一个小bug,过滤后的文本的最后一个空行没有去掉,兄弟自己去掉吧。我这边宿舍快要断电了,呵呵。   __________________ 永远的GNU! CeleronII 533MHZ + MS-6309 + HY256M SDRAM + Riva TNT2 + 15G Segate + HIGHLY OPTIMIZED lfs (id:11398) 华南农业大学01电子信息工程系(home_king@163.com)


哇! 强啊!学习!!!
发表于 2004-4-10 23:04:08 | 显示全部楼层
最初由 r2007 发表
有点复杂,请楼主先试试吧。
  1. /^### EVENT ###/ {                     
  2.   x                                    
  3.   G                                    
  4.   : a                                 
  5.   N                                    
  6.   /\n### END EVENT ###/ !b a           
  7.   N                                    
  8.   /\nPARSING_FAILED/ {                 
  9.     s/\n\n/\n/g                        
  10.     N                                 
  11.     p                                 
  12.   }                                    
  13. }                                      
  14. h     
复制代码

r2007兄,你的脚本有bug。楼主的第一个要求就是"去掉头尾空行"。你的脚本没有做到这一点。
请看你的脚本的过滤结果(注意尾部空行没有去掉):
----------------------------------------------------------------
1~906072~458748239(Apr 08 time 2004)
### EVENT ###
kdieiejr
jkjviej
### END EVENT ###
PARSING_FAILED

1~906073~8782293(Apr 08 time 2004)
### EVENT ###
ierueio
dkjfire
### END EVENT ###
PARSING_FAILED

-------------------------------------------------------------------

我给出我的改进awk脚本,它满足了楼主的所有要求,并且有很好的强壮性以及扩展性(这就是awk相对于sed的好处,而且awk脚本的可读性更好)。

  1. #--log's filter--
  2. #
  3. # Written by home_king <home_king@163.com>
  4. #
  5. /^[0-9]/,/PARSING_FAILED/{
  6.         if($0 ~ /^[0-9]/){
  7.                 if(cnt==2){
  8.                         print ""
  9.                         print $0
  10.                         next
  11.                 }
  12.                 cnt++
  13.         }
  14.         if(cnt==2 && $0 !~ /^$/){
  15.                 print $0
  16.         }
  17. }
复制代码

过滤结果:
---------------------------------------------------------------------
1~906072~458748239(Apr 08 time 2004)
### EVENT ###
kdieiejr
jkjviej
### END EVENT ###
PARSING_FAILED

1~906073~8782293(Apr 08 time 2004)
### EVENT ###
ierueio
dkjfire
### END EVENT ###
PARSING_FAILED
-------------------------------------------------------------------
发表于 2004-4-10 23:26:23 | 显示全部楼层
如果格式固定,可以试试这样
  1. /home/javalee grep -B6 PARSING_FAILED file|sed '/^    /d;s/^--/ /g'
  2. 1~906072~458748239(Apr 08 time 2004)
  3. ### EVENT ###
  4. kdieiejr
  5. jkjviej
  6. ### END EVENT ###
  7. PARSING_FAILED
  8. 1~906073~8782293(Apr 08 time 2004)
  9. ### EVENT ###
  10. ierueio
  11. dkjfire
  12. ### END EVENT ###
  13. PARSING_FAILED
  14. /home/javalee
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表