Board logo

标题: [原创] 跟我一起学文本处理:gsed/gawk快速入门[20130416更新] [打印本页]

作者: namejm    时间: 2013-2-28 12:54     标题: 跟我一起学文本处理:gsed/gawk快速入门[20130416更新]

本帖最后由 namejm 于 2013-4-16 20:53 编辑

前言

  自从淡出论坛之后,namejm一直在批处理的文本处理方面无所进展,转而求诸perl、ruby、AutoHotKey之流,零敲碎打,一事无成。
  忽有一日,zm900612传给我一份关于sed处理文本的流程的介绍资料,阅后顿觉丹田发热,任督二脉中气流乱窜,四肢百骸无比舒坦,一时间耳聪目明,以往向我紧闭的gsed/gawk大门轰然洞开, 从此步入用gsed/gawk处理文本的坦途。
  以往在仅仅使用纯批处理代码的时候,处理单个文件尚觉得心应手,但是,文件一旦多起来,或者体积急剧增大之后,要处理的情况就更复杂了,不使用命令行工具来增强批处理代码,往往会束手无措。自从用上了gsed/gawk之后,海量数据的处理也游刃有余。每每看到论坛里很多人还在无比艰辛地用纯批处理来操作文本,总觉无比心酸——要是换成gsed/gawk来做,该是多么轻松的一件事情啊!于是萌发了写一个关于gsed/gawk快速入门教程的想法,把我对gsed/gawk的理解与大家分享。
  这个教程,我不会弄成一个事无巨细的帮助手册,只挑选那些我认为会经常用到的功能来重点介绍,既有内功心法,也有具体招式,着眼于让大家迅速入门,可能会有一些图片来增强讲解效果。由于本人尚未精通gsed/gawk,不可能高屋建瓴做全面的讲解,也没有做系统的讲解规划,下面的介绍也只是我的入门理解,可能还存在着这样或那样的错误,希望发现了问题的xdjm能予以指正,谢谢。
  但愿它不要再像N年前的那个for教程那样,拖拖拉拉更新了两年多,最后虎头蛇尾弄成了个烂尾工程,吊人胃口不说,还有误人子弟之嫌。

  教程的初步大纲如下

一、 我为什么需要gsed/gawk
二、 gsed/gawk很难学吗
三、 如何获取gsed/gawk
四、 使用gsed/gawk的3种方式
五、 gsed/gawk的处理过程
六、 gsed/gawk下的正则表达式
七、 gsed的简要讲解
八、 gawk的简要讲解
九、 常见代码讲解
十、 其他

作者: namejm    时间: 2013-2-28 12:54     标题: 20130228更新

本帖最后由 namejm 于 2013-4-16 21:01 编辑

一、我为什么需要gsed/gawk

  Windows下使用批处理,我做得最多的是处理文本文件:抽取含有某些字符串的行、以某些字符为分隔符提取特征行的第N列、替换字符串A为字符串B……写过“中英文互译”、“公交线路查询”、“身份证信息查询”等小工具,甚至配合命令行版的下载工具整理过数百本在线小说、抓过论坛的上千万张图片,还玩出了查重补漏、断点续传之类的花样,据说还有牛人用批处理写过论坛灌水机,连图片验证都照过不误。古希腊伟大的物理学家阿基米德曾说过:给我一个支点,我就能撬起整个地球!面对批处理,我甚至一度产生过这样的错觉:没有做不到,只有想不到,给我一个好的idea,我就能用批处理做出来!

  但是,这仅仅是我的错觉而已。实际上,用批处理写代码是非常辛苦的:没有专门的调试器,调试代码只能手工一遍又一遍不厌其烦地添加/删除echo和pause语句、在黑乎乎的cmd窗口中观察代码的运行结果;大数或浮点数计算,还得自行设计算法、甚至模拟手工算式进行按位计算;字符串操作,仅提供了几个简陋的查找、替换功能,更复杂的操作,只能for了再for,call了再call,即使你折腾得昏天黑地,也不见得就能实现你的目标……

  具体到文本处理这一块,在windows下自带的批处理脚本中,用于处理文本的语句/工具虽然较多,但存在着这样或那样的限制:替换字符串中的字符,可以用set语句,但是你不能选择替换指定的位置,并且待替换的字符串不能超过8186字符(精确的数据尚未全面验证,但不会超过8192,下同);搜索指定字符串,findstr虽然能限定字符串是出现在行首还是行尾,但你无法限定它们的重复次数;一些复杂的操作,比如对一篇文本先抽取含有指定内容的行,再删除一些特定字符,用for语句虽然大致能办到,但你不得不考虑每行的字符数是否超过8186字符的限制、有没有包含百分号感叹号等特殊字符、如何才能只针对某行的某个特定部位进行操,如果文件巨大的话,你还得考虑处理速度是否足够快……

  总而言之,windows下的很多文字处理语句/工具,虽然能实现某些操作,但是这些功能的实现是需要付出沉重代价的:要么操作部位无法做到精准、要么字符串不能超长、要么会丢失一些特殊字符、要么处理效率异常低下难以忍受。如果不借助外部工具,在windows下用批处理对文本进行操作,即使你绞尽脑汁使出浑身解数,甚至仍然无法实现某些功能。

  即使在批处理的世界里摸爬滚打了6、7年,在接触到gsed和gawk之前,每当需要用批处理来处理一大堆文本时,我都如履薄冰,我常扪心自问:这些文本有超长字符串的行存在吗?包含特殊字符吗?替换时能做到精准匹配吗?如果是海量数据,处理速度够快吗……每当这些问题萦绕于心时,我总会有一种心虚气短头皮发麻的感觉。

  自从找到了gsed和gawk之后,我这些烦恼就一扫而空了。

  与windows下自带的文本处理语句/工具相比,gsed和gawk具备如下一些特点,足以使得它们在文本处理领域中傲视群雄:

1、支持正则表达式

  支持正则表达式,是gsed/gawk最突出的特点。可以说,gsed/gawk之所以能成为命令行下的文字处理利器,在Liunx下是无可替代的工具,很大程度上是因为有了对正则表达式的支持。如果没有了对正则表达式的支持,gsed/gawk就会失去灵魂,被抽掉了脊梁,彻底沦为可有可无的玩具,也就没有了扬名立万的资本。

  正则表达式是一种充满魔力的技术,它是用一组简单的符号代码来描述文本的组成规律,常被用来做字符串的匹配工作:查找纯英文字母的行、搜索某个字符串重复指定次数的行、寻找第N位出现某个字符串的行……这些操作对正则表达式来说是小菜一碟。如果正则表达式同时被应用于搜索和替换中,那么,从一大堆杂乱无章的文本中抽取自己想要的内容,并且以一种便于阅读的排版格式展现出来,将不再是一种奢求。君不见,EditPlus、UltraEdit、EmEditor、gVim之流,纷纷加入了对正则表达式的支持;至于那些以格式化文本为主要功能的TexPro、cnBook、排版助手之类的软件,更是以正则表达式作为其主要功能的基础和支柱。反观那些以文字处理为主,但又不支持正则表达式的软件,比如系统自带的记事本,通过搜索来定位时,查找某个指定的字符串还凑合,但是像查找像“以script打头的行”、“纯英文字母的行”之类的内容时,它们就无能为力了。不经历磨难的人生,是不完整的人生;不支持正则表达式的文本处理工具,不是一个完整的文本处理工具。而某款文本处理工具一旦支持了正则表达式,它就会达到一个更高的境界,绝对会在众多的同类软件中脱颖而出,想不红都很困难。

2、支持超长字符串

  批处理对字符串的长度是有很大限制的:set语句设置变量时,字符串长度不能超过8186个;在用findstr搜索一些超大文本时,比如每行有上百M字符的文本,会报“字符串超长”之类的错误。虽然一般情形下,我们要处理的文本,每行的字符串比较短,可能就只有几十百来字的规模,但是,碰到一些比较变态的网页文件,每行上千字符是常有的事,甚至一个上M的网页文件,可能整个文件就只有一行,如果把这些上M的字符串赋予某个变量,批处理脚本绝对会挂掉;如果碰上更变态的,比如那些服务器的日志文件,几百M甚至上G,就别指望set或findstr能干活了。

  而gsed/gawk,它们可没那么多的限制,再大的文件也咽得下,它们唯一的限制就是——你的内存究竟有多大?换句话说,如果你的内存有2G,并且打算把它们全部用于gsed或gawk,那么,gsed/gawk将不会辜负你的希望,它们真的就能每次处理2G的行!如果某个文件有10G,总共有10行字符串,那么,2G的内存下用gsed或gawk来处理绰绰有余。

3、处理速度超快

  假如有一个10M的文本文件需要进行一些比较复杂的搜索和替换操作,经过最佳优化的纯批处理代码,其处理的耗时可能是几分钟甚至几个小时,而换成gsed/gawk,很可能就是几秒到10来秒的时间!甚至几百M上G的文本,gsed/gawk都有可在数分钟内处理完毕,两者的差距是极其巨大的——没办法,谁叫gsed/gawk是专门用于处理海量文本数据的呢?如果处理速度不能接近或达到C,反倒要落后于一般的通用脚本语言,你叫gsed/gawk情何以堪?



二、gsed/gawk很难学吗

  sed和awk原本是Linux系统下以文本处理见长的命令行工具,sed的原意是文本流编辑器(Stream EDitor),awk得名于它们最初的三个发明者姓名的首字母的组合(Alfred V. Aho、Peter J. We i n b e rg e r和Brian W. Kernighan),后被GNU组织移植到了Windows下,故名gsed和gawk。

  在很多人的映像中,gsed/gawk的代码虽然简洁,但晦涩难懂,有如天书,从而本能地产生一种畏惧排斥心理。

  其实,gsed/gawk代码一点也不神秘,只需要捅破几层窗户纸,一切都会豁然开朗。

  这几层窗户纸分别是:正则表达式、gsed以行为单位处理文本、gsed的两大内存空间和gawk把文本视为数据库记录的格式进行处理的方式,而贯穿始终的,则是正则表达式

  于是,学习的难点就转到正则表达式上来了。

  正则表达式仅有有限的几组元字符,通过对这些元字符的排列组合,可以写出无穷的表达式,用来描述五花八门的文本组合。可以说,正则表达式极其简洁,但是非常灵活,拥有强大的字符串描述功能,其功能之强大,超乎想象。

  要学好gsed/gawk的正则表达式,仅需要掌握为数不多的几组元字符的用法,并在头脑中具备“贪婪模式”和“惰性模式”之类的观念就行了。

  想当初,本人仅凭借从网上收集的为数不多的一点零碎的正则表达式知识,在理解了gsed的两大内存空间的运作原理之后,短短数天就掌握了gsed的用法,写出了几段像模像样的代码,进而掌握了gawk,从此一发不可收拾,用gsed/gawk干起了在线整理文本小说、论坛抓图、批量下载mp3、整理输入法码表、整理英语词库之类的勾当,线上线下忙得不亦乐乎,现在更是热情高涨,准备把我的一些粗浅的心得整理出来,幻想着有朝一日能著书立说,三尺讲台上,也能人模狗样地传经布道一回……无限YY中^_^——本人一介文科生,被IT行业甩开了N条大街,所学非所用,gsed/gawk尚能玩得像模像样,何况诸君乎?
作者: namejm    时间: 2013-2-28 12:54     标题: 20130416更新

本帖最后由 namejm 于 2013-4-16 20:58 编辑

三、如何获取gsed/gawk

  Gsed的官方网站为:http://www.gnu.org/software/sed/
  Gawk的官方网站为:http://www.gnu.org/software/gawk/
  但是,在官方网站中,你基本上不可能找到可供Windows使用的exe格式文件。要想获得exe格式的文件,可以从下面两个网站寻找。
  1.        http://gnuwin32.sourceforge.net/packages.html
  2.        http://code.google.com/p/gnu-on-windows/downloads/list
  第1个网站中的版本有些旧,但是除了gsed/gawk之外,还有很多其他有用的命令行工具可供把玩;第2个网站提供的基本上是最新的版本。

四、使用gsed/gawk的3种方式

  你可以通过以下3种方式使用gsed/gawk。

  1.在cmd命令行窗口中使用命令。

  例如:打印出文件 test.txt 中含有字符串 bathome 的所有行,gsed命令可以写为:
  1. gsed –n “/bathome/p” test.txt
复制代码
gawk 命令可以写为:
  1. gawk “/bathome/{print $0}” test.txt
复制代码
把命令写在命令行窗口中的好处,是可以方便调试单行命令。

  2.把gsed/gawk命令写在批处理文件中。

  把命令写在批处理文件中的写法和在cmd窗口中的写法是一样的,只是写在批处理文件中,可以一次性写入多条命令,可以很方便地测试多条命令的执行结果。

  3.把gsed/gawk命令写在单独的脚本文件中。

  以上两种方法都有比较大的局限性:这些命令都只能写在同一行上,无法分成多行书写,当某条gsed/gawk命令很长,或者其中有条件判断或流程跳转时,挤在同一行上将十分难以阅读,甚至有些复杂语句根本就不能出现在同一行上。
  这个时候,就需要把gsed/gawk语句放在一个单独的脚本文件中,比如把语句保存在 test.sed/test.awk中,后缀名可以任意取,甚至不要后缀名,但是需要保存为文本格式,然后在批处理文件中通过
  1. gsed –f test.sed test.txt>result.txt
复制代码
  1. gawk –f test.awk test.txt>result.txt
复制代码
之类的语句,把对 test.txt 的处理结果放到 result.txt 中。-f test.sed 表明在批处理文件中,通过gsed调用脚本文件 test.sed 来处理test.txt 。-f 取自ScriptFile,指明紧跟其后的是一个外部的脚本文件。
作者: namejm    时间: 2013-2-28 12:55

占楼备用。
作者: namejm    时间: 2013-2-28 12:55

占楼备用。
作者: namejm    时间: 2013-2-28 12:55

占楼备用。
作者: namejm    时间: 2013-2-28 12:56

占楼备用。
作者: namejm    时间: 2013-2-28 12:56

占楼备用。
作者: namejm    时间: 2013-2-28 12:56

占楼备用。
作者: namejm    时间: 2013-2-28 12:57

占楼备用。
作者: namejm    时间: 2013-2-28 12:57

占楼备用。
作者: namejm    时间: 2013-2-28 12:57

占楼备用。
作者: namejm    时间: 2013-2-28 12:58

占楼备用。
作者: namejm    时间: 2013-2-28 12:58

占楼备用。
作者: namejm    时间: 2013-2-28 12:58

占楼备用。
作者: ladesiji    时间: 2013-2-28 14:32

“丹田发热,任督二脉中气流乱窜,四肢百骸无比舒坦”
作者: Demon    时间: 2013-2-28 15:28

用纯批处理来操作文本的不是神就是疯子
作者: cjiabing    时间: 2013-2-28 16:21

回复 17# Demon


    也可能是鬼!~我看了几次sed,资料也准备了好多,但就是没耐心学下去!~所以,我只能不停滴折磨for和find!~
作者: sxw    时间: 2013-2-28 18:11

gawk不错,就是没看完,它的正则喜欢,支持!
作者: bclcc    时间: 2013-4-22 11:04

下午慢慢欣赏- -~~
作者: 我来了    时间: 2013-4-23 16:17

这个东西  不错。
作者: cjiabing    时间: 2013-5-13 15:17

nj偷懒了!~后面楼层还空着呢!
作者: lxningbat    时间: 2013-5-14 17:17

期待啊~~~正找这东西
作者: 旋律-闭关修炼    时间: 2013-5-25 15:04

本帖最后由 旋律-闭关修炼 于 2013-5-25 15:05 编辑

cjiabing:“nj偷懒了!~后面楼层还空着呢!”
慢慢欣赏,
作者: lxningbat    时间: 2013-6-9 20:30

还没更新,没事又把for看了一遍,,,
作者: 白夜    时间: 2013-6-21 19:54

非常感谢分享!支持一下!
作者: terse    时间: 2013-7-5 17:59

想找一 MS-DOS 最新版本的 谁能帮助一下 先谢
还有发现  MS-DOS 下的用法和WIN 用法不一样啊
作者: PowerShell    时间: 2013-7-5 18:49

有空我打算找帮powershell人跟你pk下,awk sed 语法晦涩。就是搜索替换。
虽然免不了正则和搜索替换,但powershell是面向对象的,从这个角度来看,
python powershell兄弟俩,组团,pk awk sed兄弟俩。-----没错,我就是来砸场子的。呵呵。


---------以下为我的预言-----------
powershell 要pk的话,由于没有专业优化,性能比py略差。
但powershell有win下的多种对象,如excel,world。python3有很多库,这兄弟俩各有特色。
他俩代码绝对比awk sed简单。

你有搜索替换,我有面向对象神功。后续内容敬请期待。
作者: awk    时间: 2013-7-5 22:43

回复 28# PowerShell


    想学PowerShell,版主能否给几个具体的文本处理的例子,说明一下PowerShell和awk、sed的比较?也好增加我初学者的信心。
作者: PowerShell    时间: 2013-7-6 08:48

本帖最后由 PowerShell 于 2013-7-6 08:50 编辑

好有空一起研究一下大家。
应该和python脚本做法差不多,

我不知道win下的awk,sed ,比linux下的差多少。一般来说应该是差些,因为毕竟不是为win优化的,但是win awk可以用win下的其他工具,这是linux所不具备的。

类似,powershell也是如此。总之各有特色。


另外,比如日志处理,这类文本应用。由于linux一般无图形界面,所以脚本编程处理日志居多。而win,早有人写好了日志处理工具。这些工具大都是图形的,有的是c,c++,语言开发的,所以有可能比linux下处理日志还快。也就是win+c程序pk linux+脚本程序。也不一定非要用powershell。总之win下选择很多。

那么由于linux脚本处理日志是重头戏,又经多年优化,有可能性能比powershell略强,而且powershell从微软的意图,不是用来主要处理日志的,各位看官不可不知。

不过呢,要用 用例事实说话,不可yy,还是要pk下。
作者: PowerShell    时间: 2013-7-6 15:36

本帖最后由 PowerShell 于 2013-7-6 15:40 编辑

实际上,用批处理写代码是非常辛苦的:没有专门的调试器调试代码只能手工一遍又一遍不厌其烦地添加/删除echo和pause语句、在黑乎乎的cmd窗口中观察代码的运行结果;------------powershell的开发环境有3,1系统自带的powershell ise。2 免费的powershell gui,这个是我用的,有单补,断点啥的。开发调试图形软件的,powershell studio。

大数或浮点数计算,还得自行设计算法、甚至模拟手工算式进行按位计算;-----。net有无限大整数,浮点数等,专业数学计算一般调用f#来完成。我想awk sed也不能算这些吧。


字符串操作,仅提供了几个简陋的查找、替换功能,更复杂的操作,只能for了再for,call了再call,即使你折腾得昏天黑地,也不见得就能实现你的目标-----powershell字符串操作有正则。有字符转义等。



总而言之,windows下的很多文字处理语句/工具,虽然能实现某些操作,但是这些功能的实现是需要付出沉重代价的:要么操作部位无法做到精准、要么字符串不能超长、要么会丢失一些特殊字符、要么处理效率异常低下难以忍受。如果不借助外部工具,在windows下用批处理对文本进行操作,即使你绞尽脑汁使出浑身解数,甚至仍然无法实现某些功能。-------不是win不行,而是用的方法太老,powershell2006年就出来了,现在都13年了。还有强大的面向对象方法!!!


即使在批处理的世界里摸爬滚打了6、7年,在接触到gsed和gawk之前,每当需要用批处理来处理一大堆文本时,我都如履薄冰,我常扪心自问:这些文本有超长字符串的行存在吗?包含特殊字符吗?替换时能做到精准匹配吗?如果是海量数据,处理速度够快吗……每当这些问题萦绕于心时,我总会有一种心虚气短头皮发麻的感觉。

  自从找到了powershell之后,我保你烦恼就一扫而空了。随我信powershell神教吧~~~~
我乃microsoft教,powershell派,powershell交流宗,宗主。俗称传教士。不要去学魔教的awk  sed了。我教创世之神乃比尔盖茨 嘎嘎。
作者: CrLf    时间: 2013-7-6 15:56

本帖最后由 CrLf 于 2013-7-6 16:10 编辑

回复 31# PowerShell


    大数计算有 bc,*nix 的 shell 理念是将工作分为不同部分交给专家各自完成,再将粘合起来,而且这个过程非常快,十分利于构造代码和分块调试,而且内置的 python 更是支持无限长整型的运算的胶水语言,所以不需要什么全能的工具,因为无所不能的只有操作系统...
    另外,据说 c语言、perl、python、awk 的语法是比较相似的,也就是说只要对其中一门有所涉猎,其他几门语言的学习曲线都有高起点,所以 awk 的语法其实并不冷僻。
作者: tommytangtang    时间: 2014-4-22 22:21

这帖子到这里就没了?
作者: DAIC    时间: 2014-4-23 08:01

回复 33# tommytangtang


    师傅领进门,修行在个人。
作者: 我来了    时间: 2015-9-28 16:21

2年过去了,仍然是占楼。。备用。
作者: Batcher    时间: 2015-9-28 17:00

回复 35# 我来了


    无所谓啊,反正你又不学。
作者: CrLf    时间: 2015-9-28 18:17

回复 36# Batcher


    别这么高冷嘛...
作者: cjiabing    时间: 2015-9-29 20:08

回复 37# CrLf


   这个PowerShell 怎么禁言了?
作者: CrLf    时间: 2015-9-29 23:37

回复 38# cjiabing


    我塞给站长5000块,买他一条命
作者: cjiabing    时间: 2015-10-2 20:30

回复 39# CrLf


   




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2