awk运用

1,awk 处理流程

awk的处理流程分三部分,在没有读取任何数据前先执行BEGIN部分,然后进入主循环,

在主循环中读一行并进行处理,处理时先匹配模式部分,若模式部分不匹配将处理下一行。

当处理完所有输入行后,执行END的内容。

 

若没有BEGIN或END,直接进入主循环执行。

 

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

(1) 在任何数据读入前执行                   BEGIN

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

(2) 主循环,完成所有的动作                 read a line--> deal with the line

                                                            read and deal it 

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

(3) 文件内容读取完毕后执行                 END

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

 

格式形如:

awk  'BEGIN{print"start.......\n"} {print $1} END{print "end.....\n"}'

 

说明:例子文件data内容:

 

[root@myserver ~]# cat data

M.Ta   5/99 48011Green 4 40 44

N.Tans 5/99 58211 Green 840 41

S.Tns 5/99 38311 Green 5 4942

I.Tan 5/99 18321 Green 8 5040

L.Tas 5/99 28311 Green 6 4044

J.Lulu 06/99 48317 green 924 26

P.Bunny 02/99 48 Yellow 1235 28

J.Troll 07/99 4842 Brown-312 26 26

 

*控制流

 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 }

 

2, awk 支持的正则表达式

c         matches the non-metacharacter c.

\c        matches the literal character c.

.               匹配任何一个字符,包括换行符

^             匹配从字符串的开始位置

$              匹配到字符串的尾部  

[abc...]     字符列表,匹配[]中的任何一个字符

[^abc...]    非[]列表中的任何字符

r1|r2          可选正则匹配,匹配正则表达式1或表达式2

r1r2          匹配r1和r2都符合的行

r+             匹配符合正则表达式r一次或多次的行

r*             匹配0次或多次r的行

r?        匹配0次或一次正则表达式r的行。

(r)       grouping: matches r.

r{n}

r{n,}

r{n,m}     One ortwo numbers inside braces denote an interval expression.  If there is onenumber in the braces,

                 the preceding regular expression r isrepeated n times.  If there  are  two  numbers separated  by  a

                 comma,  r is repeated n to m times. If there is one number followed by a comma, then r is repeated at

                 least n times.

                 Interval expressions are only available ifeither --posix or --re-interval is specified on the command

                 line.

 

 

3,awk 中的模式匹配

*a w k条件操作符
操作符描述操作符描述
< 小于

> = 大于等于
< = 小于等于

~ 匹配正则表达式

!~ 不匹配正则表达式
= = 等于

!= 不等于

 

*正则表达式匹配 ~

$1 ~ /regexp/   ~后面接正则表达式,表达式要用/正则表达式/括起来。

在使用正则表达式时,可以有两种形式,使用if或不适用if:

awk '$n~/regexp/ {dosomthing}'  datafile

awk '{if($n~/regexp/) do somthing}'  datafile 

 

例如:

找出第3列中以48开头的行

[root@myserver ~]# awk'$3~/^48/ {print $0}'  data

M.Ta   5/99 48011Green 4 40 44

J.Lulu 06/99 48317 green 924 26

P.Bunny 02/99 48 Yellow 1235 28

J.Troll 07/99 4842 Brown-312 26 26

 

[root@myserver ~]# awk'{if($3~/^48/) print $0}'  data 

M.Ta   5/99 48011Green 4 40 44

J.Lulu 06/99 48317 green 924 26

P.Bunny 02/99 48 Yellow 1235 28

J.Troll 07/99 4842 Brown-312 26 26

 

*精确匹配 ==

[root@myserver ~]# awk'$3==48{print $0}'  data

P.Bunny 02/99 48 Yellow 1235 28

[root@myserver ~]# awk'{if($3=="48") print $0}'  data

P.Bunny 02/99 48 Yellow 1235 28

 

*不匹配  !~

找出在第3列中不含11字符串的行

[root@myserver ~]# awk'$3!~/11/{print $0}' data  

I.Tan 5/99 18321 Green 8 5040

J.Lulu 06/99 48317 green 924 26

P.Bunny 02/99 48 Yellow 1235 28

J.Troll 07/99 4842 Brown-312 26 26

 

*不等于 !=

找出第3列中不等于48的行

[root@myserver ~]# awk'{if($3!="48") print $0}' data  

M.Ta   5/99 48011Green 4 40 44

N.Tans 5/99 58211 Green 840 41

S.Tns 5/99 38311 Green 5 4942

I.Tan 5/99 18321 Green 8 5040

L.Tas 5/99 28311 Green 6 4044

J.Lulu 06/99 48317 green 924 26

J.Troll 07/99 4842 Brown-312 26 26

 

*大于  >

#找出第6列的值>40的行

[zxh@localhost dosh]$ awk'{if($6>40) print $0}' data

S.Tns 5/99 38311 Green 5 4942

I.Tan 5/99 18321 Green 8 5040

#或者

[zxh@localhost dosh]$ awk'$6>40{print $0}' data

S.Tns 5/99 38311 Green 5 4942

I.Tan 5/99 18321 Green 8 5040

 

*大小写匹配   ~[aA]

*任意单个字符匹配 ~/^...a/

#匹配(1)第1列中第4个字符为r的行 或 (2) 第4列首字母为Y或y的行

[zxh@myserver dosh]$ catdata | awk '{if($1~/^...r/ || $4 ~/^[Yy]/) print $0}'

P.Bunny 02/99 48 Yellow 1235 28

J.Troll 07/99 4842 Brown-312 26 26

 

*正则的或关系~/(reg1|reg2)/

#在用或关系时,注意要用()括起来

[zxh@localhost dosh]$ awk'{if($3~/(^38|^18)/) print $0}' data

S.Tns 5/99 38311 Green 5 4942

I.Tan 5/99 18321 Green 8 5040

#上面也是或关系使用的例子

 

*正则表达中的与关系    ~/reg1/&& ~/reg2/

awk '{if($1=="P.Bunny" && $4=="Yellow") print $0}'grade.txt

 

*多次匹配

#每次匹配成功时先把结果输出,在进行第2个正则表达式的匹配。

[zxh@localhost dosh]$ awk'$1~/^L/{print $1}; $3~/^28/{print $3}' data

L.Tas

28311

 

* 已28开头11结尾的匹配

awk '$3~/^28.*11$/ {print$0}' data

 

4, awk常用内置变量

FILENAME     因为a w k可以同时处理许多文件,因此如果访问了这个变量,将告之系统目前正在浏览的实际文件。

FS              用来在a w k中设置域分隔符,与命令行中-F选项功能相同。缺省情况下为空格。

FNR               当前输入文件的记录数

NR                 N record。表示当前输入的总记录数,若是多个文件,它是多个FNR的和。

NF                  N field。表示当前输入记录的域(列)数。

OFS               output field seperator。输出域分割符。默认是空格。

ORS               output record seperator。输入记录(行)分割符,默认是换行符。

ARGC         命令行参数个数

RS                 输入的记录分割符,默认是换行符\n,支持|或&&的支持

 

注意:在使用时,这些变量不需要加$符号。只有在取这些变量对应的记录值时才需要加。

 

*NF,NR,FILENAME

#计算文件的行数

[zxh@localhost dosh]$ timeawk 'END{print NR}' data

8

 

说明:#它的性能比起wc -l要慢许多

[zxh@localhost dosh]$ timewc -l data1

4194944 data1

 

real    0m0.163s

user    0m0.120s

sys     0m0.041s

[zxh@localhost dosh]$ timeawk 'END{print NR}' data1     

4194944

 

real    0m0.525s

user    0m0.485s

sys     0m0.039s

 

#打印当前目录(取最后一个域的值)

[zxh@localhost dosh]$ echo$PWD | awk -F/ '{print $NF}'

dosh

 

#取文件名

[zxh@localhost dosh]$ echo"/usr/local/sbin/gfmd" | awk -F/ '{print $NF}'

gfmd

 

#cut 也可以做到,但比较笨一些

[zxh@localhost dosh]$ echo"/usr/local/sbin/gfmd" | cut -d/ -f 5

gfmd

 

 

5, awk 的操作符

详细说明可以参看:man awk

      (...)           组

      $              域引用。

      ++ --       自增和自减,作为前缀和后缀都可以。

      ^              Exponentiation (** mayalso be used, and **= for the assignment operator).

      + - !          一元操作符:加,减,非.

      * / %        乘,除,取模。

      + -           加,减.

      space       字符串连接.

      < >

      <= >=

      != ==       关系操作符

      ~ !~         正则表达式匹配操作符。.

      in             数组成员关系操作符。

      &&          逻辑与

      ||              逻辑或.

      ?:              和C的三元操作符相同

      = += -=

      *= /= %= ^=  计算操作符.

 

*使用自定义变量

#注意在引用自定义变量时,不需要添加$符号

#把各个域变量设置成可识别的变量,例如若1列表示名字,那么可以这样做: name=$1

[zxh@localhost dosh]$ awk'{name=$1;score=$3; if($name ~/^L/) print name,score}'  data    

L.Tas 28311

 

*修改域值

# 注意一下记录,$NF的值都变成了30

[zxh@localhost dosh]$ awk'{score=$NF; if(score<30) $NF=30; print score,$0}' data          

... ...  

26 J.Lulu 06/99 48317 green9 24 30

28 P.Bunny 02/99 48 Yellow12 35 30

26 J.Troll 07/99 4842Brown-3 12 26 30

 

*创建新的输出域

#上面的一个例子已经增加了一列,增加一列很容易吧。其实增加列还有另外一种方式。

#以下脚本,我想把最后的三个域的值加起来,然后放到最后一列输出,注意在输出$0时自动把最后一列加进来了。

#若把NF+1改成NF+2,则会自动添加一个空格列,也就是NF+1这一列。

[zxh@localhost dosh]$ awk'{ad=NF+1; $ad=$NF+$(NF-1)+$(NF-2); print $0}' data            

M.Ta 5/99 48011 Green 4 4044 88

N.Tans 5/99 58211 Green 840 41 89

S.Tns 5/99 38311 Green 5 4942 96

... ...

 

*统计列的值

#统计最后一列的总和

[zxh@localhost dosh]$ awk'{tot+=$NF} END{print "last field total:"tot}' data

last field total:291

 

*文件长度相加

#计算一个目录下,非目录文件的总大小 

[root@localhost ~]# ls -l |awk '/^[^d]/{print $5;s+=$5}; END{print "totalsize="s/1024"k"}'

 

1165

147

35566

5195

13

total size=41.0996k

 

#计算当前目录非目录文件总大小

[root@localhostlibevbase-0.0.14]# find . -type f -exec ls -l '{}' \; | awk '/^[^d]/{tot+=$5};END{print "size="tot/1024/1024"M"}'

size=2.22593M

 

 

6, 使用awk中的函数

*内置字符串函数

gsub( r, s)                    在整个$ 0中用s替代r

gsub( r, s , t)                在整个t中用s替代r

index(s , t)                 返回s中字符串t的第一位置,若没有找到返回0

length(s)                  返回s长度

match(s , r)                测试s是否包含匹配r的字符串

split(s , a , fs)            在fs上将s分成序列a

sprint(fmt , exp)      返回经f m t格式化后的e x p

sub(r, s )                        用$ 0中最左边最长的子串代替s

substr(s , p)               返回字符串s中从p开始的后缀部分

substr(s , p , n)          返回字符串s中从p开始长度为n的后缀部分

 

说明:详细使用说明,请man awk,搜索gsub等。

 

*字符串替换

注意:字符串替换要加双引号: gsub(/oldstring/,"newstring",$1)

#在整个记录中把383替换成888

[zxh@myserver dosh]$ catdata | awk 'gsub(/383/,888){print $0}' 

S.Tns 5/99 88811 Green 5 4942

 

*在某一列中替换

#把第1列中的字符串Lulu替换成字符串hover,注意加双引号

[zxh@myserver dosh]$ catdata | awk 'gsub(/Lulu/,"hover",$1){print $0}' 

J.hover 06/99 48317 green 924 26

 

*替换字符串第一次出现的位置 sub

# 使用s u b发现并替换模式的第一次出现位置。和gsub相似,但只替换第一次出现的字符。

# sub(r, s [, t])   r是正则表达式;s是是要替换的字符串。t是域号,若没有指定,则是$0

[zxh@myserver dosh]$ catdata | awk '$0~/^L/{sub(44,55);print $0}'

L.Tas 5/99 28311 Green 6 4055

 

 

*查找字符串

#查找第一列中包含字符串"Lulu"的行

[zxh@myserver dosh]$ catdata | awk 'index($1,"Lulu"){print $0}'

J.Lulu 06/99 48317 green 924 26

 

*分割字符串split

[zxh@myserver dosh]$ catdata | awk '$1~/J\.L/{split($0,arr," ")} END {print arr[3]}'

48317

 

#另外一个例子

[root@Linux_chenwy sam]#awk 'BEGIN {print split("123#456#789",myarray,"#")}'

 

*输出字符串长度length

[zxh@myserver dosh]$ catdata | awk '$0~/^L/{print length($1),$1}'

5 L.Tas

 

 

*字符串切割 

# substr(s, i [, n]) 

# Returns the at mostn-character substring of s starting at i.  If n is omitted, the rest of sis used

#打印第2个域,从"/"开始的字符串其余部分

[zxh@myserver dosh]$ catdata | awk '$0~/^L/{sub(44,55);print substr($2,index($2,"/"))}'

/99

 

 

7, 使用awk脚本文件

可以将a w k脚本写入一个文件再执行它。命令不必很长(尽管这是写入一个脚本文件的主

要原因),甚至可以接受一行命令。

使用awk脚本文件有以下优点:

(1)这样可以保存a wk命令,以使不必每次使用时都需要重新输入。

(2)使用文件的另一个好处是可以增加注释,以便于理解脚本的真正用途和功能。

 

*基本格式

第一行必须是:  !/bin/awk -f 表示awk命令从文件中读取命令行。

 

*例1

[zxh@localhost dosh]$ catdo.awk 

#!/usr/bin/awk -f

# myfirst.awk 

#

BEGIN {

       print "--------------start-----------"

}

 

{

       if ($5>10)

               print "<10 "$5

       else

               print ">10 "$5

}

 

END {

       print "-------------end--------------"

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值