awk数据处理整理

来源:互联网 发布:化妆品可以去淘宝买吗 编辑:程序博客网 时间:2024/06/06 04:48
基础知识
    1.基本程序结构

    awk 程序是由若干个“模式”与“动作”所组成的,其执行方式是针对文件中的每一行(line)搜索指定的模式 (patterns),当一行中有符合指定的模式,awk 就会在此一行执行被指定的动作(actions)。 awk 依此方式处理输入文件的每一行直到输入文件结束。
   “动作”一般写在大括号 “{ }” 里面,一个模式后面就跟着一个动作,一个动作可以是一条或多条语句。整个 awk 程式就象下面的形式:
awk  ‘ 模式 { 动作 }
     .................
        模式 { 动作 }’ filename
例如:awk 'BEGIN {FS="[,/]"}NR==FNR{a[$0]=$0}NR!=FNR && a[$2]{print $0}' b a
这种形式是从filename文件中读入数据
或者
`命令|awk ‘模式 { 动作 }
            ..............
            模式 { 动作 }’`        
是通过管道将命令的输出传递给awk语句。
   
例:awk ‘$1=”127.0.0.1” { print $2 }’ /etc/hosts  #从/etc/hosts中读入数据
而:cat  /etc/hosts| awk ‘$1=”127.0.0.1” { print $2 }’ #则是接收cat  /etc/hosts的结果
两个例子都是将/etc/hosts文件中所有第一个字段为127.0.0.1的行的第二个字段打印出来。
其运行结果为:localhost

    在 awk 中,“模式”或“动作”能够被省略,但通常是省略模式。模式被省略后,对于输入文件里面的每一行,动作都会被执行。而如果“动作”被省略,awk语句只会去寻找你所指定的模式,但即使找到了也不执行其它任何操作(因为没有指定动作),就象在Unix系统中你用find命令去寻找一个文件,但是没有用 –print 参数来说明要显示一样,find只是找到了这个文件,但并不显示出来。
例如:awk '{print $1}' /etc/hosts   从/etc/hosts文件中读入数据,将每个记录(行)的第二个字段打印出来
awk ‘$1=”127.0.0.1”’ /etc/hosts 
只是在/etc/hosts文件中寻找,看看哪一行的第一个字段为127.0.0.1,不管找到与否,一概不显示。 所以结果是:什么都没有

执行awk文件:
vim a.awk
#!/bin/awk -f

vim a.sh
#!/bin/bash

变量


1)字段变量
awk处理数据时是逐行进行处理的,字段变量就是在处理过程中表示当前记录各字段的变量,其形式和含义如下:
$0: $0就是所处理的当前行(字符串)
$1: 当前行(记录)的第一个字段
$2: 当前行(记录)的第二个字段
$3: 当前行(记录)的第三个字段
………
如:  awk ‘{ print $1,”|”,$2 }’ /tmp/test
该语句将/tmp目录下的test文件的第一和第二个字段打印出来,字段间的分隔符为”|”.

2) 内部变量
awk的每次执行,都建立了一些缺省的变量,也叫做内部变量,这些变量有固定的名字和固定的含义,它们在程序运行期间可以随时被引用。其具体定义如下:
FS:    输入记录字段间的分隔符 field separate
RS:   输入记录的分隔符 row separate
OFS:  输出记录字段间的分隔符 out field separate
ORS:  输出记录的分隔符  out row separate

NR:   当前行数 num row
NF:   当前记录字段数  num field
ARGC: 命令行变元数 argc

 前四个内部变量在使用时一般用于设定你所需要的分隔副符,具体的使用方法如下例所示:
awk ‘BEGIN { FS=”|” ;OFS=”|” } #指明输入输出时都以“|”为字段间的分隔符
      { print $1,$2,…… }’ 文件名 
 
后面三个内部变量用于模式部分较多,在动作部分也有使用。
awk ‘ NR=10 { print $1,$2,…… }’ 文件名  #用于限定只对第十行进行处理。
awk ‘ BEGIN { SUM=0 }   #对SUM变量赋初值
     { SUM=SUM+NF }    #利用NF变量获得每行字段数的总和
      END { print “本文总共” SUM “个字段” }’ 文件名
 关于BEGIN和END的用法将在第三章介绍。

    3)自定义变量
在awk语言的任意动作区间,即在{}之内,均可随时定义变量,无须事先说明。但一般情况下是在BEGIN中定义变量并赋以初值,在动作区域内使用。
如:awk ‘BEGIN { sum=“0” } #定义变量sum,其初值为0
     { sum=sum+1 }   #对于每一条记录变量sum加1
            END { print sum }’ file0
 整条语句将计算出文件总的字段数。


全部环境变量
$n          当前记录的第n个字段,字段间由FS分隔。
$0          完整的输入记录。
ARGC        命令行参数的数目。
ARGIND      命令行中当前文件的位置(从0开始算)。
ARGV        包含命令行参数的数组。

CONVFMT     数字转换格式(默认值为%.6g)
ENVIRON     环境变量关联数组。
ERRNO       最后一个系统错误的描述。
FIELDWIDTHS 字段宽度列表(用空格键分隔)。
FILENAME    当前文件名。
FNR         同NR,但相对于当前文件。
FS          字段分隔符(默认是任何空格)。
IGNORECASE  如果为真,则进行忽略大小写的匹配。
NF          当前记录中的字段数。
NR          当前记录数。

OFMT        数字的输出格式(默认值是%.6g)。
OFS         输出字段分隔符(默认值是一个空格)。
ORS         输出记录分隔符(默认值是一个换行符)。
RLENGTH     由match函数所匹配的字符串的长度。
RS          记录分隔符(默认是一个换行符)。
RSTART      由match函数所匹配的字符串的第一个位置。

SUBSEP      数组下标分隔符(默认值是\034)。


运算符
= += -= *= /= %= ^= **=    赋值
?:      C条件表达式
||      逻辑或
&&      逻辑与
~ ~!    匹配正则表达式和不匹配正则表达式
< <= > >= != ==            关系运算符
空格    连接
+ -     加,减
* / %   乘,除与求余
+ - !   一元加,减和逻辑非
^ ***   求幂
++ --   增加或减少,作为前缀或后缀
$       字段引用
in      数组成员


例如:
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


模式(pattern)
在一条“模式-动作”语句中,模式是一个表达式,用来确定执行相关操作的那些记录(行)。也就是在awk处理数据时,只有数据行与模式(pattern)相匹配,程序中相对应的动作(action)才会被执行。

BEGIN和END
BEGIN和END是两个特殊的模式。
BEGIN的作用是在处理第一条记录之前将BEGIN后面大括号之内的动作运行且只运行一次,也就是BEGIN匹配第一个输入记录之前。
END的作用是在处理完最后一条记录之后将END后面大括号之内的动作运行且只运行一次,也就是说,END匹配最后一个输入记录之后。

用表达式(Expression)作为模式
 一个awk模式可以是一个表达式,用这个表达式来测试两个数字或字串的诸如大于、等于、小于等关系。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     如果 x 符合 正则表达式  y,则结果为真。
x!~y    如果 x 不符合 正则表达式  y,则结果为真。

上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,否则它们会被转换成字符串且以字符串的形式做比较。两个字符串的比较,会先比较第一个字符,然后比较第二个字符,依此类推,直到有不同的地方出现为止。如果两个字符串在较短的一个结束之前是相等,则视为长的字符串比短的字符串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。
 例:awk ‘$1>5{ print $0 }’ file0  其结果是把文件file0中第一个字段大于5的所有行打印出来。

用正则表达式(Regular Expressions)作为模式
    awk还提供了比前面介绍的功能更强的字符串查找模式。这些模式称做正则表达式,最简单的正则表达式是以斜杠“/”括起来字符串,例如:/Asia/ 
    一个regular expression (正则表达式)可简写为 regexp,当输入记录含有 regexp 时就视为符合。如上例中的/Asia/,对于任何输入记录,若含有'Asia'则视为符合。
    例如:awk '/Asia/ { print $2 }' earth   结果将把文件earth中所有含'Asia'的行的第二个字段打印出来,而不论'Asia'这个字符串在一行中的那一部分。 
    通常,为了将一个匹配限制在一个特定的域上,可以使用匹配操作符~(匹配)和!~(不匹配)。
    如:awk '$2 ~ /Asia/ { print $0 }' file0  将把文件file0中第二个字段是字符串Asia的行全部打印出来。

在正则表达式中,符号 \ ^ $ . [ ] | ( ) * + ? 是元字符, 例如,元字符“^”和“$”分别匹配字符串的开始和结束,而元字符“.”匹配任意单个字符。如 /^.$/ 将匹配所有只包含一个字符的输入行。  
由大括号括起来的一组字符,表示匹配其中的任何一个字符。如/{ABC}/与那些无论在什么地方包含A,B,C中任一字符的记录相匹配。
多个字符或数字可以在括号内采用缩写形式:/[a-z]/,它与所有纯小写字母字符串相匹配。 /^[0-9]+$/匹配所有以数字开头的字符串。
在元字符的前面加上一个“\”,就可以关闭元字符的特殊含义。这样,/b\$/匹配所有包含b$这两个字符的行。
更多正则表达式介绍参看:http://blog.csdn.net/fb408487792/article/details/44307197

模式组合( 模式表达式 )
一个组合的模式是由较简单的模式加上圆括号和逻辑操作符&&"与",||"或",!"非"来构成。
例如:
awk '$1==”Asia” && $3>500 { print $0 }’earth
将文件earth中所有第一个字段为Asia,且第三个字段大于500的行打印出来。

awk '$1==”Asia”||$1==”Africa” { print $0 }’earth
awk '$1~/^(Asia|Africa)$/ { print $0 }’earth
以上两句都是将文件earth中所有第一个字段为Asia或者为Africa的行打印出来。

awk '$1!=”Asia” && $1~/^[As]/ { print $0 }’earth
将文件earth中所有第一个字段包含As但不为Asia的行打印出来。
非操作符!的优先级最高,其次是&&,最后是||。操作符&&和||从左到右判断它们的操作数,当得到真或假值时,这种判断即停止。


动   作

输入

1)从文件中输入
格式为: awk ’{ action }’ filename1 filename2 ...
执行时,awk将依次从filename1 filename2 ...文件中读取数据并执行action操作.

2)从其它命令输入
格式为: Unix命令| awk ’{ action }’
执行时,awk将接收Unix命令的输出,并对输出执行action操作.

3)从标准输入设备上输入
在命令行上输入awk ’{ action }’ 并回车后
awk语句便处于等待状态,此时可以输入一条记录,当打回车确认后,awk语句将对这一行进行处理。如果符合处理的条件,awk就会将处理结果显示到屏幕上。接着,再次进入等待输入的状态。如此循环下去,一直到打Ctrl-d退出或Ctrl-c中断。

4) 读入awk以外的Shell变量
有时需要将awk以外的变量读入到awk之中,通常有两种方法:
a. 直接引用外部变量
aa="字符串"
awk ' { print "'$aa'" }'  

b. 间接引用外部变量
aa="string"
awk '{ print bb }' bb=$aa
执行后每一次回车都将显示一个字符串string,该字符串是由awk中的print语句显示的,其中变量bb的值通过后面的bb=$aa引入。对于汉字字符串的赋值在SCO Unix3.0上运行时还需注意,多个赋值语句,使用汉字字符串的语句应放在后面(在5.0上没有这种情况):
aa=“计算机使用指南”
bb=“computer guide”
awk '{ print cc dd  }' cc=$bb dd=$aa filename

数据的处理是以“记录”(recoder)为单位的,也就是awk 在做处理时,是一个记录一个记录地处理。每个记录的缺省值是一行(line),一个记录又被分为多个字段(fields)。


如何将输入分解成记录(records)
awk 语言会把输入分解成记录(record)。记录与记录之间是以记录分隔符(record separator)隔开的,其缺省值是文件中的换行符(newline character),因此在缺省状态下输入数据的每一行是一个记录。
记录分隔符随着内部变量 RS 的改变而改变。RS 是一个字串,如“|”。它的缺省值是"\n"。仅有 RS 的第一个字符是有效的,而其它字符会被忽略。
内部变量 FNR 会储存目前的输入文件已经被读取的记录的个数。内部变量 NR 会储存目前为止所有的输入文件已经被读取记录的个数

字段(field)
awk 会自动将每个记录按缺省值分解成多个字段 (field)。awk 的缺省动作会认为字段之间是以 whitespace 为分隔的。这里,whitespace 的意思是一个或多个空格或 tabs。
在 awk 程序里面,以'$1'表示第一个字段,'$2'表示第二个字段,依此类推。举个例子,假设输入的一行如下所示:
This seems like a pretty nice example.
第一个字段或 $1 是'This',第二个字段或 $2 是 'seems',依此类推。有个地方需要特别注意,第七个字段或 $7 是'example.'而非'example'。
不论有多少字段,$NF 可用来表示一个记录的最后一个字段。以上面的例子为例,$NF 与 $7 相同,也就是'example.'。
    NF 是一个内部变量,它的值表示目前这个记录之字段的个数
    $0,看起来好像是第零个字段,它是一个特例,它表示整个记录。
    
下面是一个较复杂的例子:
    awk '$1~/foo/ { print $0 }' Earth
这个例子是把输入文件'Earth'的每个记录的第一个字段作检查,如果它含有子字串'foo',则这一个记录会被输出。

如何将记录分解成字段
awk 根据 field separator(字段分隔符)将一个记录分解成若干字段。field separator 以内部变量 FS 表示。    
举个例子,假如 field separator 是'oo',则下面的行:
moo goo gai pan
会被分成三个字段:'m'、' g'、' gai pan'。
在 awk 程序里,可以使用'='来改变 FS 的值
例如: awk 'BEGIN { FS="," }; { print $2 }'
输入行如下:
John Q. Smith, 29 Oak St., Walamazoo, MI 42139
执行awk的结果将输出字符串 ' 29 Oak St.'(将第二个字段打印出)。BEGIN 后面的 action 会在第一个记录被读取之前执行一次。


输出
    在awk程序里,actions 最常做的事就是输出(printing)。简单的输出,使用 print描述。复杂格式的输出,使用 printf 描述。

1)print 语句
print语句用在简单、标准的输出格式。
格式:print var1,[ var2,……],str1,[str2,……,strn ]
说明:在print 语句后面,可以跟变量或字符串,变量或字符串可以有多个,语句执行后,跟在print 语句后面的变量值或字符串将被显示到屏幕上。多个变量或字符串之间可以是逗号“,” 或空格,
使用逗号时,显示出的各个字符串之间会有空格分隔
使用空格时,显示出的各个字符串将连接起来,形成一个长的字符串
 如:echo “fir sec thir four five”|awk ‘{ print $1,$2,$3,$4 }’
其执行结果为fir sec thir four
 而:echo “fir sec thir four five”|awk ‘{ print $1  $2  $3  $4 }’
的结果为firsecthirfour
print语句输出后自动换行,如有第二个显示语句,将从下一行输出。

如果 'print'描述之后没有跟着任何东西,它与'print $0'的效果一样,它会输出现在的记录(record)。要输出空白行可使用'print ""'。 输出一段固定的文字,可用双引号将文字的两边括起来,例如'print "Hello there"'。

2) 输出分隔符
前面我们已提过print语句后面多个输出字段(变量)之间可以用逗点使输出分隔开来,事实上,你可以任何设定你所需要的输出分隔符,OFS 就是用来设定输出分隔符的内部变量。其缺省值为空格。
下面这个例子会输出每个记录的第一个字段和第二个字段,此二个字段之间在输出时是以分号';'分开的,每行输出之后会加入一个空白行。
awk 'BEGIN { OFS=";"  ORS="\n\n" } {print $1, $2}' earth

3) printf语句
printf 语句会使得输出格式较容易精确地控制。printf 语句可以指定每个 item 输出的宽度,也可以指定数字的各种格式。
printf 语句的格式如下:
printf format, item1, item2, ...
如:printf "%4s%10s%10s\n","str1","str2","str3"
或:printf ("%4s%10s%10s\n","str1","str2","str3")
    
print 与 printf 的差别是在于 format, printf 的参数比 print多了字符串 format。format 的格式与 C语言 中的 printf语句格式相同。

printf 并不会做自动换行的动作。内部变量 OFS 与 ORS 对 printf 语句没有任何影响。格式的指定以字符'%'开始,后面接着格式控制字母。

格式控制字母如下所示:
'c'     将数字以 ASCII 字符输出。
        例如  'printf "%C",65'会输出字符'A'。
'd'     输出十进位的整数。
'e'     将数字以科学记数的形式输出。
        例如  printf "%4.3e",1950   结果会输出'1.950e+03'。
'f'     将数字以浮点的形式输出。
'g'     将数字以科学记数的形式或浮点的形式输出。数字的绝对值如果大于
        等于0.0001则以浮点的形式输出,否则以科学符号的形式输出。
'o'     输出无符号的八进位整数。
's'     输出一个字串。
'x'     输出无符号的十六进位整数。10至15以'a'至'f'表示。
'X'     输出无符号的十六进位整数。10至15以'A'至'F"表示。
'%'   它并不是真正的格式控制字母,”%%"将输出‘%'。
        在 % 与格式控制字母之间可加入 modifier,是用来进一步控制输出的格式。可能的 modifier 如下所示:
'width' 这一个数字指示相对应的字段输出时的宽度。例如:
'-'     使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在被指定的宽度向右靠齐。
        例如:printf "%-6s", "foo"  会输出'foo   '。
        printf "%6s","foo"    会输出'   foo'。
        width 的值是一个最小宽度而非最大宽度。如果一个 item 的值需要的宽度比 width 大,则不受 width 的影响。例如
        printf "%4s","foobar" 将输出'foobar'。
'.prec' 此数字指定输出时的精确度。它指定小数点右边的位数。如果是要输出一个字串,它指定此字串最多会被输出多少个字符。


控制语句
在 awk 程序里面,控制语句诸如 if、while 等的使用与 C语言类似,需要,需要使用{}包起来
很多的控制语句会包括其它的语句,被包括的语句称为程序体(body)。假如body 里面包括一个以上的语句,必须以大括弧 { } 将这些语句括起来(这与Shell的语法有所区别),而各个语句之间需以换行(newline)或分号隔开。

1) if 语句
语法: {if ( 条件 ) { body1 } [ else { body2 } ]}
其中,if,else 是关键字,如果使用必须保留,程序体中可以有多条语句。
如果条件(condition)为真(true),则执行程序体1中的语句,否则执行程序体2。
例1:
    if ( x == 0)      #变量x是否为0
       print "x equal zero"   #为0则打印"x equal zero"
    else        #否则
       print "x not equal zero"  #则打印"x not equal zero"
   
    if(){}
    else if(){}
    else{}


2)while 语句
语法:   {while ( 条件 )
            { body }}
awk '{ i=1
    while (i <= 3)  {
        printf(“%s”,$i)
        i++
    }
    print “”    #换行
}'

do-while
awk '{ i= 1
   do {  print $0
         i++    }
   while (i <= 10)
 }' 文件名

4)for 语句
 语法: {for (赋初值;条件;动作)
           { body }}
此语句开始时会执行初始赋值(initialization),然后比较条件是否为真,只要条件(condition)为真,就执行‘动作’和body ,然后重新判断条件,重新执行,直到条件为假为止。
    下面的例子会输出每个输入记录的前三个字段。
awk '{ for (i=1; i<=3; i++)
    printf("%s  ",$i)
    print ""      #换行
}' 文件名

5)break 语句
break 语句用于跳出包含它的 for、while、do-while 语句的当前循环。
下面的例子能够对任意输入的自然数做出以下判断:
a. 求出其最小除数
b. 判断其是否为质数。
awk '{ num=$1
   for (div=2; div*div <=num; div++)
      {  if ( num % div == 0 )
              break  #当整除时跳出for循环
       }
   if ( num % div == 0 )
        printf "%d 最小的除数是 %d\n", num, div
   else
        printf "%d 是质数\n", num
 }'

6)continue 语句
    continue 语句使用于 for、while、do-while 循环内部,它会跳过循环 body 的剩余部分,使得它立刻进行下一次循环的执行。
    下面的例子会输出 0 至 20 的全部数字,但是 5 并不会被输出。
awk 'BEGIN { for (x=0; x<=20; x++) { 
if (x==5)
continue #当x为5时跳过下面的printf语句,进入下次循环
printf ("%d ",x)
}
}'

7) next 语句、next file 语句、exit 语句
next 语句强迫 awk 立刻停止处理目前的记录(record)而继续下一个记录的处理。
next file类似 next。然而,它强迫 awk 立刻停止处理目前的文件
exit 语句会使得 awk 程序停止执行而跳出然而,如果END 出现,它会去执行 END 中的 actions(动作)


8)数组
awk中的数组的下标可以是数字和字母,称为关联数组。

1 变量作为数组下标
$ awk '{name[x++]=$2}END{for(i=0;i<NR;i++) print i,name[i]}' test
#数组name中的下标是一个自定义变量x,awk初始化x的值为s0,在每次使用后增加1。第二个域的值被赋给name数组的各个元素。在END 模块中,for循环被用于循环整个数组,从下标为0的元素开始,打印那些存储在数组中的值。因为下标是关健字,所以它不一定从0开始,可以从任何值开始。
special for循环用于读取关联数组中的元素。格式如下:
{for (item in arrayname){
    print arrayname[item]
    }
}
$ awk '/^tom/{name[NR]=$1}; END{for(i in name){print name[i]}}' test
#打印有值的数组元素。打印的顺序是随机的。

2 字符串作为下标    count["test"]
3 域值作为数组的下标,一种新的for循环方式,for (index_value in array) statement。如:
$ awk '{count[$1]++} END{for(name in count) print name,count[name]}' test
#该语句将打印$1中字符串出现的次数。它首先以第一个域作数组count的下标,第一个域变化,索引就变化。

delete 函数用于删除数组元素。如:
$ awk '{line[x++]=$2}END{for(x in line){delete line[x];print line[x]}}' test
#分配给数组line的是第一个域的值,所有记录处理完成后,special for循环将删除每一个元素。



内建函数(Built-in Functions)

1) 数学函数:
int(x)
     求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9) 是 3,int(-3.9) 是 -3。
sqrt(x)     求出 x 正的平方根值。例 sqrt(4)=2
exp(x)      求出 x 的次方。例 exp(2) 即是求 e*e 。
log(x)      求出 x 的自然对数。
sin(x)      求出 x 的 sin 值。
cos(x)      求出 x 的 cos 值。
atan2(y,x)  求 y/x 的 arctangent 值,所求出的值其单位是弧度量。
rand()      得出一个随机数值。此随机数值平均分布在 0 和 1 之间。这个值不会是0,也不会是 1。每次执行awk,rand 产生的数字都不相同。
如:awk '{ for (i=1;i<10;i++)
           { x=rand()
             print x
           }
     }'     
执行后,每打一次回车便产生10个0-1之间的随机数。但第一次执行产生的若干数字如100个和第二次执行产生的100个数字相同。
srand(x)    设定产生随机数的开始点为 x。如果在第二次你设定相同的 seed 值,你将再度得到相同序列的随机数值。如果省略引数 x,例如 srand(),则现在的日期、时间会被当成初始值。这个方法可使得随机数值是真正不可预测的。

2)字符串函数:
index(in, find)
它会在字符串 in 里面,寻找字符串 find 第一次出现的地方,返回值是字符串 find 出现在字符串 in 里面的位置。如果在字符串 in 里面找不到字符串 find,则返回值为 0。
例如:
    print index("peanut","an")
输出 3。

length(string) 求出 string 字符串的长度。
例如:
     length("abcde")返回值 5。

match(string,regexp)
match 函数会在字符串 string 里面,寻找符合 regexp 的最长、最靠左边的子字符串。返回值是 regexp 在 string 的开始位置,即 index 值。
match 函数会设定内在变量 RSTART 等于 index,它也会设定内在变量 RLENGTH 等于符合的字符个数。如果不符合,则会设定 RSTART 为0、RLENGTH 为 -1。
如:awk '{  match("sfsdfgertertrtra","tert")
            print RSTART,RLENGTH
         }'
执行后,每次回车都会显示9 4,意为第9位,长度为4

sprintf(format,expression1,...)
与 printf 类似,但是 sprintf 并不输出,而是返回字符串。
例如:
     pi=sprintf(“%.2f (approx.)”,22/7)
print pi
将会显示 3.14 (approx.)

sub(regexp, replacement,target)
在字符串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,以字符串 replacement 代替最左边的 regexp。
例如:
awk '{ str = "water, water, everywhere"
       sub(/at/, "ith",str)
       print str
     }'              
结果字符串str会变成
"wither, water, everywhere"

gsub(regexp, replacement, target)
gsub 与前面的 sub 类似。在字符串 target 里面,寻找符合 regexp 的所有地方,以字符串 replacement 代替所有的 regexp。
例如:
    str="water, water, everywhere"
    gsub(/at/, "ith",str)
结果字符串str会变成
wither, wither, everywhere

substr(string, start, length)
返回字符串 string 的子字符串,这个子字符串的长度为 length 个字符,从第 start 个位置开始。
例如:str=substr("washington",5,3)
          返回值为"ing"
如果 length 没有出现,则返回的子字符串是从第 start 个位置开始至结束。
例如:
awk 'BEGIN { oldstr="washington" }      
   { newstr=substr(oldstr,5)
       print newstr                 
          }’
执行后将显示"ington"

tolower(string)
将字符串string的大写字母改为小写字母。
例如:
  awk 'BEGIN { oldstr="WASHINGTON" }      
       { newstr= tolower(oldstr)
           print newstr                 
              }’
执行后显示: washington


toupper(string)
将字符串string的小写字母改为大写字母。
例如:
    toupper("MiXeD cAsE 123")
    返回值为"MIXED CASE 123"

split(s,a,fs) split( 原字串, 数组名称, 分隔字符 )
awk ' BEGIN { split( "20:18:00", time, ":" ); print time[2] }'

systime() 返回从1970年1月1日开始到当前时间(不计闰年)的整秒数
awk 'BEGIN{ now = systime(); print now }'
awk 'BEGIN{print systime()}'

strftime(“%F %S”) 显示年-月-日时:分:秒  使用C库中的strftime函数格式化时间。

%a   星期几的缩写(Sun)%A   星期几的完整写法(Sunday)%b   月名的缩写(Oct)%B   月名的完整写法(October)%c   本地日期和时间%d   十进制日期%D   日期 08/20/99%e   日期,如果只有一位会补上一个空格%H   用十进制表示24小时格式的小时%I   用十进制表示12小时格式的小时%j   从1月1日起一年中的第几天%m   十进制表示的月份%M   十进制表示的日期%p   12小时表示法(AM/PM)%S   十进制表示的秒%U   十进制表示的一年中的第几个星期(星期天作为一个星期的开始)%w   十进制表示的星期几(星期天是0)%W   十进制表示的一年中的第几个星期(星期一作为一个星期的开始)%x   重新设置本地日期(08/20/99)%X   重新设置本地时间(12:00:00)%y   两位数字表示的年(99)%Y   当前月份%Z   时区(PDT)%%   百分号(%)$ awk 'BEGIN{ now=strftime( "%D", systime() ); print now }'$ awk 'BEGIN{ now=strftime("%m/%d/%y"); print now }'


输入输出函数:
close(filename)
将输入或输出的文件 filename 关闭。
如: awk '{ print "new line">"new"  }'
前面的语句的作用是将”new line”这个字符串放入文件new中,注意语句中使用的是”>”符号,其作用将显示内容转向,在转向的同时将文件中原有的内容清除掉,所以不论print语句执行几遍,文件new中的内容都应该只有一行:”new line” 。
但执行上例awk语句,敲5次回车后发现文件new中有5行new line,而不是一行。其原因是因为文件new被打开后,没有被关闭,导致再次操作时发生错误。如果需要完成上例所设想的功能,应该使用下面的语句:
awk '{ print "new line">"new"  
   close(new)
}'
另外,在一个awk中如使用追加符号“>>”可以不使用close语句,但为了避免多个awk语句可能存在对同一个文件的操作,在对文件操作完成后,最好都使用close关闭文件。

system(command) 此函数允许在awk中使用系统提供的Shell命令,命令执行完毕后将回到 awk 程序。
例如:
awk '{ str=sprintf("head -%d filename",$1 )
       system(str)}'
该语句将按输入数字的值取出文件filename的前若干行。
注意,在使用格式化语句的时候,首先要将格式化的字符串赋予某个变量,如例子中的str,然后再在system中使用。

如果希望将命令执行的结果截获下来,供awk中的语句使用,可以使用管道。如:
awk ' { "cat filename|wc -l" | getline var #将文件filename的长度赋予变量var
          print var
        }'    
管道线前面的语句可以不包括在system中。          
getline函数的在这里的作用是将通过管道获得的值存储于var变量。


getline
awk提供将输入数据分解为记录的功能,但对于某些任务来说,仍不能满足数据处理的要求。比如,在下列数据文件当中数据是以若干行为单位存放的:
more data:
begin
zhangqiang  24  nan  96
wanggang  23  nan  97
zhaoyu  22  nu  98
end
……
如上所示,begin和end之间的数据是一个整体,在文件中的数据全部是以这种方式存放,当然在处理时也需要读入一个单位后统一进行,在这种情况下,就可以用到getline函数。
getline函数用以读取下一行的数据并进行字段分解操作,设置NF,NR和FNR。如果有一个记录,getline返回1,如果遇到文件结束,返回0,如果出现错误,返回-1。
举例:
awk '/^begin/ { N=0      #在找到开始标志begin时,将变量N置0
    while (getline && $0 !~ /^end/)     #取下一行,并且下一行不是end时
        { f[++N]=$0 }                    #将读入的数据存入数组f中
   for (i=1;i<=N;i++)     #对begin与end之间的数据进行处理
        { printf("%s " , f) }    #存入到数组f中。
   print ""        #换行
}' data
 
getline函数还有其它用法:
getline x      #将下一个记录读入变量x中,不作分解,不设置NF
getline  < “filename” #从指定文件filename中读取一行(存入$0中),而不是从当前文件中,对NR或FNR没有影响,但对字段进行分解并且设置NF。
再或者,如上页例题中所示,通过管道截取命令执行后的结果。


自定义函数(User-defined Functions)

1) 函数定义的格式

函数的定义可以放在 awk 程序的任何地方。
一个自定义的函数其格式如下:
    function name (parameter-list) {
       body-of-function
    }
name 是所定义的函数的名称。一个正确的函数名称可包括一序列的字母、数字、下标线 (underscores),但是不能用数字做开头。
parameter-list 是函数的参数列表(argument),各个参数之间以逗点隔开。
body-of-function 包含 awk 的描述 (statement)。它是函数定义里最重要的部份,它决定函数实际要做何种事。

2) 函数定义的例子
下面这个例子,会将每个记录的第一个字段值的平方与第二个字段之值的平方加起来。
awk ‘{ print $1,$2,"sum =",SquareSum($1,$2) }
     function SquareSum(x,y)
    {
      sum=x*x+y*y
      return sum
    }’ filename
在定义了函数SquareSum之后,对每一行数据的处理只需经过一次调用就可以。但定义自定义函数最大的好处还是可以在不同的地方调用,而不必每次都写上一堆,此外还使程序结构清楚,易读,易维护。


示例:

awk '{ if (NF > max) max = NF }  END { print max }' filename此程序会输出所有输入行中,包含字段最多的行的字段数。awk 'length($0) > 80' filename此程序会输出一行超过 80 个字符的每一行。此处只有 pattern 被列出,action 是采用缺省的 print。awk 'NF > 0' filename对于拥有至少一个字段的所有行,此程序皆会输出。这是一个简单的方法,将一个文件里的所有空白行删除。awk '{if (NF > 0) print}' filename对于拥有至少一个字段的所有行,此程序皆会输出。这是一个简单的方法,将一个文件里的所有空白行删除。awk 'BEGIN { for (i = 1; i <= 7; i++)       print int(101 * rand()) }' filename此程序会输出 0 到 100 之间的 7 个乱数值。ls -l files| awk 'BEGIN { x=0 }    { x += $4 }    END { print "total bytes: " x }' filename此程序会输出所有指定的文件之bytes数目的总和。expand file | awk '{if (x < length()) x = length()}                   END {print "maximum line length is " x              }' filename此程序会将指定文件里最长一行的长度输出。expand 会将 tab 改成 space,所以是用实际的右边界来做长度的比较。awk 'BEGIN {FS = ":"}  {print $1 | "sort"}' /etc/passwd 此程序会将所有用户的login名称,依照字母的顺序输出。awk '{nlines++}  END {print nlines}' filename此程序会将一个文件的总行数输出。awk 'END {print NR}' filename此程序也会将一个文件的总行数输出,但是计算行数的工作由awk来做。awk '{print NR,$0}' filename在输出文件的内容时,会在每行的最前面输出行号,它的功能与 'cat -n' 类似。 筛选一下第2行到第4行的数据Awk ‘NR>=2 && NR<=4’ grade.txt 或者awk ‘NR>=2 && NR<=4{print 0}’ grade.txt筛选包含Bu的一行awk 'substr($2,3,2)=="Bu"{print $0}' grade.txt任意字符$awk '$1~/^...a/' grade.txt 第一个域行首前三个字任意第四个是a #以^为开头的意思,精确匹配关系匹配$awk '$0~/(Yellow|Brown)/' grade.txt$awk '/(Green|green)/' grade.txt #等于'/[Gg]reen/' -->G或者g行首$awk '/^J.L/' grade.txt&& and || or !$awk '{if($1=="P.Bunny"&&$4=="Yellow")print$0}' grade.txt #精确$awk '{if($4=="Yellow"||$4~/Brown/)print$0}' grade.txt #模糊$awk 'END{print NR}' grade.txt #->5 NR 已读的记录数$awk '{print NF,NR,$0}END{print FILENAME}' grade.txt #FILENAME=grade.txt$awk '{if (NR >0 && $4~/Brown/)print $0}' grade.txt$echo $PWD | awk -F/ '{print NF}' #4(不一定),此处的nf包含第一个为空的域$echo "/usr/local/etc/rc.sybase" |awk -F/ '{print NF}' #5(前面多一个空的域)向一行awk命令传值,awk 命令变量=输入文件值$awk '{if($5 < AGE) print $0}' AGE=10 grade.txt#awk ‘{AGE=10;if($5<AGE)print $0}’ grade.txtawk '/^root/,/^mysql/' test#打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。如果找到一个新的正则表达式root开头的记录,则继续打印直到下一个以正则表达式mysql开头的记录为止,或到文件末尾。awk 'BEGIN{ "date" | getline d; print d}' test#执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量d,并打印它。awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' test#执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将输入赋值给d,split函数把变量d转化成数组mon,然后打印数组mon的第二个元素。awk 'BEGIN{while( "ls" | getline) print}'#命令ls的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为 BEGIN块在打开输入文件前执行,所以可以忽略输入文件。awk 'BEGIN{printf "What is your name?"; getline name < "/dev/tty" } $1 ~name {print "Found" name “on line ", NR "."} END{print "See you," name "."} test#在屏幕上打印”What is your name?",并等待用户应答。当一行输入完毕后,getline函数从终端接收该行输入,并把它储存在自定义变量name中。如果第一个域匹配变量 name的值,print函数就被执行,END块打印See you和name的值。awk 'BEGIN{while (getline < "/etc/passwd" > 0) lc++; print lc}'#awk将逐行读取文件/etc/passwd的内容,在到达文件末尾前,计数器lc一直增加,当到末尾时,打印lc的值。注意,如果文件不存在,getline返回-1,如果到达文件的末尾就返回0,如果读到一行,就返回1,所以命令 while (getline < "/etc/passwd")在文件不存在的情况下将陷入无限循环,因为返回-1表示逻辑真。可以在awk中打开一个管道,且同一时刻只能有一个管道存在。通过close()可关闭管道。如:$ awk '{print $1, $2 | "sort" }' test END {close("sort")}#awd把print语句的输出通过管道作为linux命令sort的输入,END块执行关闭管道操作。


0 0
原创粉丝点击