awk文本处理总结(入门,中级,高级)

1.什么是awk是一种程序设计语言, 主要用来处理数据和产生报表,它对输入数据(文件、标准输入或命令的输出)逐行进行扫描,匹配指定的模式,并执行指定的操作。
2.awk语法格式
    awk   ‘pattern   {action}’   filename
     awk扫描filename中的每一行,  对符合模式pattern的行执行操作action.
    特例:
    awk   ‘pattern’   filename     显示所有符合模式pattern的行
    awk   ‘{action}’  filename     对所有行执行操作action
    awk   ‘{action}’               重命令行输入数据

举例
    选择一个文件,在这我创建一个文件test
    $cat  test
    beijing   010
    beijing  021
    chongqing 023

    在此请注意要进入test所在目录
    $awk  ‘/beijing/’   employees
    beijing   010

    $awk  ‘{print  $1}’   test

    beijing
    beijing
    chongqing

    $awk  ‘/beijing/  {print  $1 $2}’   employees

    beijing   010

3.此外awk还支持管道流
    格式:      command  |  awk  ‘pattern’
         command  |  awk  ‘{action}’
         command  |  awk ‘pattern  {action}’

举例  
    $who
    zhanglan   tty01    Jan  12   18:36
    yuexi         tty02     Jan  12   17:03
    liuzhen      tty15     Jan  12   08:45
    $who |  awk ‘/tty01/ {print  $1}’    (谁在1号终端上)
    zhanglan 

4.awk还支持命令文件
    awk  -f   awk_file   data_file

举例
    $ cat  my_awk
    /Sally/ {print “**** found  Sally!  ****”}
    {print  $1, $2, $3}

    $ awk  -f  my_awk   employees
    **** found  Sally!  ****
    Sally Chang     1654

上面类似于awk的helloworld,要想更深入了解请参考其他文章。

  作为技术支持工程我们最最经常的工作就是经常碰到要处理文本文件,不管是什么数据库最后都可以导成文本,我们就可以对他进行处理了,这样即使你不是对所有数据库操作都很熟悉也可以对他的数据进行处理了。

    我们必须的工具有两个一个是shell一个是awk,awk对于处理文本文件是最最适合的掌握了awk我们就可以很方便的处理文本文件再借助一些shell命令我们可以很方便得到自己想要的结果。现在从简单的例子来总结一下我觉得会经常碰到的问题。

   

    awk入门篇

   

    awk入门,文本内容example1.txt.

   

user1 password1 username1 unit1 10

user2 password2 username2 unit2 20

user3 password3 username3 unit3 30   

    在unix环境中我们可以使用一下命令来打印出第一列

   

[root@mail awk]# awk '{print $1}' example1.txt

    得到的结果是如下,解释一下"'{" 单引号大括号包含awk语句是为了和shell 命令区别,$1的意思就是文本文件的第一列,正常的awk命令跟随-F参数指定间隔符号,如果是空格或tab键就可以省略了。

    $0表示整行下面会用到。

user1

user2

user3

[root@mail awk]# awk '{if($5>20) {print $1}}' example1.txt

        这行命令和上一行比较增加了“if($5>20)”,得到的结果是

user3

这个if语句就没有必要更详细的解释了吧!就是第5列大于20的显示出满足条件的第一列

[root@mail awk]# awk '{if($5>20 || $5==10) {print $1}}' example1.txt

user1

user3

在来一个初级的又增加了一个“if($5>20 || $5==10)”    做逻辑判断逻辑判断的三个“|| && !” 或、与、非三个可以任意加到里面,这个语句的意思是如果第5列大于20或者等于10的都显示处理,在我们的工作中可能有用户会要求找出所有空间大于多少的 或者是空间等于多少的账户然后再做批量修改。

if是awk循环中的一个还有其他很多,man awk可以看到,

   Control Statements

       The control statements are as follows:

              if (condition) statement [ else statement ]

              while (condition) statement

              do statement while (condition)

              for (expr1; expr2; expr3) statement

              for (var in array) statement

              break

              continue

              delete array[index]

              delete array

              exit [ expression ]

              { statements }

学习awk可以经常使用一下man awk 可以看到所有的函数和使用方法。   

了解每个符号的意义我们才能更好的使用awk,最开始先记住几个命令知道他可实现的结果我们慢慢的再去理解。

================================================================================

    awk中级篇

这里顺便介绍一下vi的一个替换命令,现在我们要把example1.txt文本里的空格都替换为“:”冒号这里在vi里使用的命令就是:

%s/ /:/g     

这个命令对于使用vi的人来说是用得最多的。我们现在做了一个新的文件example2.txt。

user1:password1:username1:unit1:10

user2:password2:username2:unit2:20

user3:password3:username3:unit3:30

现在我们来做一个awk脚本,之前都是在命令行操作,实际上所有的操作在命令行上是可以都实现的,已我们最经常使用的批量添加用户来开始!script1.awk

#!/bin/awk -f   # 当文件有可执行权限的时候你可以直接执行

                # ./script1.awk example2.txt

                # 如果没有以上这行可能会出现错误,或者

                # awk -f script1.awk example2.txt 参数f指脚本文件

BEGIN {         # “BEGIN{”是awk脚本开始的地方

    FS=":";     # FS 是在awk里指分割符的意思

}

{                                # 接下来的“{” 是内容部分

      print "add {";             # 一下都是使用了一个awk函数print

      print "uid=" $1;

      print "userPassword=" $2;

      print "domain=eyou.com" ;

      print "bookmark=1";

      print "voicemail=1";

      print "securemail=1"

      print "storage=" $5;

      print "}";

      print ".";

}                               # “}”    内容部分结束

END {                           # “END{” 结束部分

    print "exit";

}

执行结果

[root@mail awk]# awk -f script1.awk example2.txt

add {

uid=user1

userPassword=password1

domain=eyou.com

bookmark=1

voicemail=1

securemail=1

storage=10

}

.              

add {

uid=user12

userPassword=password2

domain=eyou.com

bookmark=1

voicemail=1

securemail=1

storage=20

}

.

add {

uid=user3

userPassword=password3

domain=eyou.com

bookmark=1

voicemail=1

securemail=1

storage=30

}

.

exit

文本操作就是更方便一些。

下面给两个返回效果一样的例子

[root@mail awk]# awk -F: '{print $1"@"$2}' example2.txt

[root@mail awk]# awk -F: '{printf "%s@%s\n",$1,$2}' example2.txt

user1@password1

user2@password2

user3@password3

这里我试了一下,发现是按行一行一行的扫描然后输出的。因为当我把example2.txt文件里的三行信息中间都加一个空行的时候,出现的结果是(文件最后一个空行不扫描)

user1@password1

@

user2@password2

@

user3@password3

@

这里的区别是使用print 和printf的区别,printf格式更自由一些,我们可以更加自由的指定要输出的数据,print会自动在行尾给出空格,而printf是需要给定" \n"的,如果感兴趣你可以把“\n”去掉看一下结果。%s代表字符串%d 代表数字,基本上%s都可以处理了因为在文本里一切都可以看成是字符串,不像C语言等其他语言还要区分数字、字符、字符串等。

awk还有一些很好的函数细细研究一下还是很好用的。

这次碰到了一个问题客户有一个用户列表,大概有2w用户,他有一个有趣的工作要做,就 是把每个账户目录放到特定的目录下,例如13910011234这个目录要放到139/10/这个目录下,从这里可以看出规律是手机号码的前三位是二级目 录名,手机的第3、4为是三级目录名,我们有的就只有一个用户列表,规律找到了我们现在开始想办法处理吧。

example3.txt

13910011234     

15920312343

13922342134

15922334422

......

第一步是要找到一个方法来吧,就是要把每一个手机号分开,最初可能你就会想到这个也没有任何间隔,我们怎么用awk分开他们呢?说实话最初我也考虑 了20多分钟,后来想起原来学习python的时候有split函数可以分就想找找awk里是不是有类似的函数,man awk 发现substr 这个函数子串,

[root@mail awk]# awk '{print substr($1,1,3)}' example3.txt

[root@mail awk]# awk '{printf "%s/%s\n",substr($1,1,3),substr($1,4,2)}' example3.txt

[root@mail awk]# awk '{printf "mv %s %s/%s\n",$1,substr($1,1,3),substr($1,4,2)}' example3.txt

以上的两步的返回自己做一下,最后我们就得到了我们想要的结果。

mv 13910011234 139/10

mv 15920312343 159/20

mv 13922342134 139/22

mv 15922334422 159/22

把这部分输出拷贝到一个shell脚本里,在数据当前目录下执行就可以了!

substr(s, i [, n])      Returns the at most n-character substring of s

                               starting at i. If n is omitted, the rest of s

                               is used.

                              

substr函数解释,s代表我们要处理的字符串,i 是我们从这个字符串的第几个位置上开始,n 是我们从开始的位置取多少个字符。多看看man英文也会有所提高的。                              

awk有很多有趣的函数如果感兴趣可以自己去查查看,

man awk

String Functions 字符串函数,举几个觉得常用的函数

    length([s])             Returns the length of the string s, or the

                               length of $0 if s is not supplied.

    length 你可以得到字符串的长度,这个是比较常用的一个函数                         

    split(s, a [, r])       Splits the string s into the array a on the

                               regular expression r, and returns the number of

                               fields. If r is omitted, FS is used instead.

                               The   array a is cleared first.   Splitting

                               behaves   identically   to   field   splitting,

                               described above.    

                              

        tolower(str)            Returns a copy of the string str, with all the

                               upper-case characters in str translated to

                               their corresponding lower-case counterparts.

                               Non-alphabetic characters are left unchanged.

                              

        toupper(str)            Returns a copy of the string str, with all the

                               lower-case characters in str translated to

                               their corresponding upper-case counterparts.

                               Non-alphabetic characters are left unchanged.

                                                                                    Time Functions 时间函数,我们最最常用到的是时间戳转换函数

                                                                                  

strftime([format [, timestamp]])

                 Formats timestamp according to the specification in format.

                 The timestamp should be of the same form as returned by sys-

                 time().   If timestamp is missing, the current time of day is

                 used. If format is missing, a default format equivalent to

                 the output of date(1) is used. See the specification for the

                 strftime() function in ANSI C for the format conversions that

                 are guaranteed to be available. A public-domain version of

                 strftime(3) and a man page for it come with gawk; if that

                 version was used to build gawk, then all of the conversions

                 described in that man page are available to gawk.                                                                                  

                                                                                  

这里举例说明时间戳函数是如何使用的

[root@ent root]# date +%s | awk '{print strftime("%F %T",$0)}'

2008-02-19 15:59:19        

我们先使用date命令做一个时间戳,然后再把他转换为时间                                                                                             

还有一些我们现在可能不经常用到的函数,详细内容man awk 自己可以看一下。

Bit Manipulations Functions   二进制函数

Internationalization Functions 国际标准化函数

USER-DEFINED FUNCTIONS      用户也可以自己定义自己的函数,感兴趣自己可以再深入研究一下。

For example:

              function f(p, q,     a, b)   # a and b are local

              {

                   ...

              }

              /abc/     { ... ; f(1, 2) ; ... }

DYNAMICALLY LOADING NEW FUNCTIONS 动态加载新函数,这个可能就更高级一些了!

================================================================================

awk高级篇

不管学习任何语言,我们学到的都是工具,工具知道的越多,我们做起工作来就越方便,但是工具在你的手里并不一定能造出好的产品,编辑脚本和编程序也是一样的重要的是算法,别人不知道怎么处理的问题你要知道如何处理。这才能证明你比别人更高,工具只要你慢慢练习都会使用。

    下面给大家一个我认为是比较高级的问题了,感兴趣的可以自己再想想更好的解决办法。问题是这样的我们有一个从ldap里导出的文件,它都是一行一个字段来 说明的,每个用户的数据是已空行分割的。我们必须把对应的uid 和userPassword找出来而且是对应的。

   

    例子:example4.txt

   

dn: uid=cailiying,domain=ccc.com.cn,o=mail.ccc.com.cn

uid: cailiying

userPassword:: e21kNX0zREl4VEIwODBJdXZkTnU3WFFtS3lRPT0=

letters: 300

quota: 100

dn: uid=caixiaoning,domain=ccc.com.cn,o=mail.ccc.com.cn

userPassword:: e21kNX1kejFXU0doZWprR2RNYnV5ajJJRWl3PT0=

letters: 300

quota: 100

uid: chenzheng

domain: cqc.com.cn

dn: uid=caixiaoning,domain=ccc.com.cn,o=mail.ccc.com.cn

userPassword:: e21kNX1kejFXU0doZWprR2RNYnV5ajJJRWl3PT0=

letters: 300

quota: 100

dn: uid=caixiaoning,domain=ccc.com.cn,o=mail.ccc.com.cn

userPassword:: e21kNX1kejFXU0doZWprR2RNYnV5ajJJRWl3PT0=

letters: 300

quota: 100

uid: chenzheng

domain: cqc.com.cn

                                                                                    处理这个文本我们需要考虑的问题是:

1 uid 和userPassword 并不是每一个段落里都有

2 在每一段里面uid和userPassword 先后顺序是随机的

3 有的段落里可能只有uid 或者只有userPassword

从文本上分析可以看出必须使用的间隔符号,一个是空行,一个是冒号。

冒号我们awk -F:就可以了,不过空行我们不好判断现在想到length()这个函数,在unix里空行最多只有一个\n字符,如果一行字符数小于2我们判断为空行, 好现在间隔符号问题解决,空行只能通过循环来实现对空行的判断。                                        

现在碰到的另外一个问题是我们的某个段里的信息是不完全的,我们就要放弃这段这儿如何来做,就是要做两个标记变量u 和 p 再做一个循环如果u 和 p 同事满足我们才输出结果下面的awk脚本就是通过这个思考来解决ldif文本的处理的!

# 此脚本的目的是方便我们以后导ldap的其他邮件的数据,

# 我们之前使用slapdcat -l 导出所有信息,然后我们需要

# 整理出uid password , 这里的设置都是默认以":" 间隔的

# 例slapcat -l user.ldif 如果想得到一份uid 和userPassword 对应的文件,

# 修改username = "dn"; password = "userpassword"; awk -f ldap2txt.awk user.ldif | grep uid | more 可以查看结果 (有可能是多域的邮件)

# 如果想得到domain 所对应的密码,修改username = "dn"; password = "userpassword"; 运行 awk -f ldap2txt.awk user.ldif |grep domain | more

#!/bin/awk -f

# File name: ldap2txt.awk

BEGIN {

        FS = ":";

        username = "uid";

        password = "userPassword";

}

{

        if(length($0) == 0 )

        {

                if (name != "u" && pword != "p")

                {

                        printf ("%s:%s\n", name,pword);

                        name = "u";

                        pword = "p";

                }

        }

        else

        {

                if ($1 == username)

                {

                name = "u";

                name = $0;

                }

                else if($1 == password)

                {

                pword = "p";

                pword = $0;

                }

        }

}

END {

}实际上对于学习语言首先是熟悉一些常用的函数,然后就是试着去解决别人解决过的问题,然后自己再思考一下是不是有更好,速度更快的解决办法,实际上 大部分的程序员都是在重复的使用着别人好的解决办法,把别人的方法转变为自己的方法,就是反复练习解决不同的问题,思考更好的方法!     

文章转自:http://hi.baidu.com/yoshubom/blog/item/69a40df3a892cbcf0b46e063.html

 

附录:

1.awk的常规表达式元字符

\ 换码序列
^ 在字符串的开头开始匹配
$ 在字符串的结尾开始匹配
. 与任何单个字符串匹配
[ABC] 与[]内的任一字符匹配
[A-Ca-c] 与A-C及a-c范围内的字符匹配(按字母表顺序)
[^ABC] 与除[]内的所有字符以外的任一字符匹配
Desk|Chair 与Desk和Chair中的任一个匹配
[ABC][DEF] 关联。与A、B、C中的任一字符匹配,且其后要跟D、E、F中的任一个字符。
* 与A、B或C中任一个出现0次或多次的字符相匹配
+ 与A、B或C中任何一个出现1次或多次的字符相匹配
? 与一个空串或A、B或C在任何一个字符相匹配
(Blue|Black)berry 合并常规表达式,与Blueberry或Blackberry相匹配

2.awk算术运算符

运算符 用途
------------------
x^y x的y次幂
x**y 同上
x%y 计算x/y的余数(求模)
x+y x加y
x-y x减y
x*y x乘y
x/y x除y
-y 负y(y的开关符号);也称一目减
++y y加1后使用y(前置加)
y++ 使用y值后加1(后缀加)
--y y减1后使用y(前置减)
y-- 使用后y减1(后缀减)
x=y 将y的值赋给x
x+=y 将x+y的值赋给x
x-=y 将x-y的值赋给x
x*=y 将x*y的值赋给x
x/=y 将x/y的值赋给x x%=y 将x%y的值赋给x
x^=y 将x^y的值赋给x
x**=y 将x**y的值赋给x

3.awk允许的测试:

操作符 含义

x==y x等于y
x!=y x不等于y
x>y x大于y
x>=y x大于或等于y
x<y x小于y
x<=y x小于或等于y?
x~re x匹配正则表达式re?
x!~re x不匹配正则表达式re?

4.awk的操作符(按优先级升序排列)

= 、+=、 -=、 *= 、/= 、 %=
||
&&
> >= < <= == != ~ !~
xy (字符串连结,'x''y'变成"xy")
+ -
* / %
++ --

5.awk内置变量(预定义变量)

说明:表中v项表示第一个支持变量的工具(下同):A=awk,N=nawk,P=POSIX awk,G=gawk

V 变量 含义 缺省值
--------------------------------------------------------
N ARGC 命令行参数个数
G ARGIND 当前被处理文件的ARGV标志符
N ARGV 命令行参数数组
G CONVFMT 数字转换格式 %.6g
P ENVIRON UNIX环境变量
N ERRNO UNIX系统错误消息
G FIELDWIDTHS 输入字段宽度的空白分隔字符串
A FILENAME 当前输入文件的名字
P FNR 当前记录数
A FS 输入字段分隔符 空格
G IGNORECASE 控制大小写敏感0(大小写敏感)
A NF 当前记录中的字段个数
A NR 已经读出的记录数
A OFMT 数字的输出格式 %.6g
A OFS 输出字段分隔符 空格
A ORS 输出的记录分隔符 新行
A RS 输入的记录他隔符 新行
N RSTART 被匹配函数匹配的字符串首
N RLENGTH 被匹配函数匹配的字符串长度
N SUBSEP 下标分隔符 "\034"

6.awk的内置函数

V 函数 用途或返回值
------------------------------------------------
N gsub(reg,string,target) 每次常规表达式reg匹配时替换target中的string
N index(search,string) 返回string中search串的位置
A length(string) 求串string中的字符个数
N match(string,reg) 返回常规表达式reg匹配的string中的位置
N printf(format,variable) 格式化输出,按format提供的格式输出变量variable。
N split(string,store,delim) 根据分界符delim,分解string为store的数组元素
N sprintf(format,variable) 返回一个包含基于format的格式化数据,variables是要放到串中的数据
G strftime(format,timestamp) 返回一个基于format的日期或者时间串,timestmp是systime()函数返回的时间
N sub(reg,string,target) 第一次当常规表达式reg匹配,替换target串中的字符串
A substr(string,position,len) 返回一个以position开始len个字符的子串
P totower(string) 返回string中对应的小写字符
P toupper(string) 返回string中对应的大写字符
A atan(x,y) x的余切(弧度)
N cos(x) x的余弦(弧度)
A exp(x) e的x幂
A int(x) x的整数部分
A log(x) x的自然对数值
N rand() 0-1之间的随机数
N sin(x) x的正弦(弧度)
A sqrt(x) x的平方根
A srand(x) 初始化随机数发生器。如果忽略x,则使用system()
G system() 返回自1970年1月1日以来经过的时间(按秒计算)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值