awk 是一种程序语言. 它具备通常程序语言常见的功能.
因awk语言具备某些特色, 如 : 使用直译器(Interpreter)不需先行编译; 变量无类型之分(Typeless), 可以使用文字当数组的下标(Associative Array)...等特点. 所以, 使用awk撰写程序比起使用其它语言更简洁便利且节省时间. awk还具备一些内建功能, 使得awk擅于处理具数据行(Record), 字段(Field)型态的资料; 此外, awk内建有pipe的功能, 可将处理中的数据传送给外部的 Shell命令加以处理, 再将Shell命令处理后的数据传回awk程序, 这个特色也使得awk程序很容易使用系统资源。html
awk读取输入文件时,每次读取一条记录(record)(默认状况下按行读取,因此此时记录就是行)。每读取一条记录,将其保存到$0中,而后执行一次main代码段
在读取数据时,可设置表示输入记录分隔符的预约义变量RS(Record Separator)来改变每次读取的记录模式linux
awk 'BEGIN{RS="\n"}'默认状况下使用\n换行符进行分隔读取。 RS="":按段落读取 RS="\0":一次性读取全部数据,但有些特殊文件中包含了空字符\0 RS="^$":真正的一次性读取全部数据,由于非空文件不可能匹配成功 RS="\n+":按行读取,但忽略全部空行
因此在读取数据前,能够改变RS来改变每次读取数据的模式正则表达式
ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803
awk [ -- ] program-text file ... (1) awk -f program-file [ -- ] file ... (2) awk -e program-text [ -- ] file ... (3) program-txt是awk命令行中的awk代码,通常使用单引号包围 -f program-file表示将awk代码写在文件中,而后使用-f选项去执行该文件 -e program-text也用于指定awk代码,若是要结合文件和命令行一块儿使用,必须使用-e和-f,不能使用(1)
-e program-text --source program-text 指定awk程序表达式,可结合-f选项同时使用 在使用了-f选项后,若是不使用-e,awk program是不会执行的,它会被看成ARGV的一个参数 -f program-file --file program-file 从文件中读取awk源代码来执行,可指定多个-f选项 -F fs --field-separator fs 指定输入字段分隔符(FS预约义变量也可设置) -n --non-decimal-data 识别文件输入中的8进制数(0开头)和16进制数(0x开头) echo '030' | awk -n '{print $1+0}'
-o [filename] 格式化awk代码。 不指定filename时,则默认保存到awkprof.out 指定为`-`时,表示输出到标准输出 -v var=val --assign var=val 在BEGIN以前,声明并赋值变量var,变量可在BEGIN中使用
awk程序中主要语法是 Pattern { Actions}
Pattern:为匹配模式,即断定某一行是否符合该模式,而后才执行Actions
Actions:为执行逻辑,其中多个action若是写在同一行,则需使用分号分隔shell
pattern和action均可以省略express
省略代码块{action},等价于{print}即输出全部行vim
pattern{action}任何一部分均可以省略数组
pattern中使用逻辑与、非、或数据结构
pattern && pattern # 逻辑与 3>2 && 3>1 {action} pattern || pattern # 逻辑或 3>2 || 3<1 {action} ! pattern # 逻辑取反 !/a.*ef/{action}
经常使用的Patternless
# 1.根据行号筛选 NR==2 # 筛选出第二行 NR>=2 # 输出第2行和以后的行 # 2.根据正则表达式筛选整行 /qq.com/ # 输出带有qq.com的行 $0 ~ /qq.com/ # 等价于上面命令 /^[^@]+$/ # 输出不包含@符号的行 !/@/ # 输出不包含@符号的行 # 3.根据字段来筛选行 ($4+0) > 24{print $0} # 输出第4字段大于24的行 $5 ~ /qq.com/ # 输出第5字段包含qq.com的行 # 4.将多个筛选条件结合起来进行筛选 NR>=2 && NR<=7 #输出行数大于等于2而且小于等于7 $3=="male" && $6 ~ /^170/ #输出第三个字段等于male而且第六个字段不用170开头 $3=="male" || $6 ~ /^170/ #输出第三个字段等于male或者第六个字段不用170开头 # 5.按照范围进行筛选 flip flop # pattern1,pattern2{action} NR==2,NR==7 # 输出第2到第7行 NR==2,$6 ~ /^170/ # 输出第2行到匹配第六个字段170开头的行
action有不少,例如:dom
awk的 I/O指令 : print, printf( ), getline... awk的 流程控制指令 : if(...){..} else{..}, while(...){...}...
实例:
[root@lgh test]# awk '' test.txt #action和pattern都省了 [root@lgh test]# awk '/163/{print $0}' test.txt #匹配行中有163的行,并输出 1 zhangs female 34 aaa@163.com 13423394013
5 liub male 56 gdd@163.com 18848796507
8 zhaoy female 35 189@163.com 17058796503 [root@lgh test]# awk '/163/' test.txt #省略action,默认输出$0 1 zhangs female 34 aaa@163.com 13423394013
5 liub male 56 gdd@163.com 18848796507
8 zhaoy female 35 189@163.com 17058796503 [root@lgh test]# awk '{print $0}' test.txt #省略pattern,输出所有行 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803
预约义变量分为两类:控制awk工做的变量和携带信息的变量
第一类:控制AWK工做的预约义变量
$0,$1,$2,...$NF:其中$0表示整行数据,$1,$2,...,$NF分别表示该行的第一个字段、第二个字段,...,最后一个字段
RS:输入记录分隔符,默认为换行符\n IGNORECASE:默认值为0,表示全部的正则匹配不忽略大小写。设置为非0值(例如1),以后的匹配将忽略大小写。例如在BEGIN块中将其设置为1,将使FS、RS都以忽略大小写的方式分隔字段或分隔record FS:读取记录后,划分为字段的字段分隔符。 FIELDWIDTHS:以指定宽度切割字段而非按照FS。 FPAT:以正则匹配匹配到的结果做为字段,而非按照FS划分。 OFS:print命令输出各字段列表时的输出字段分隔符,默认为空格" " ORS:print命令输出数据时在尾部自动添加的记录分隔符,默认为换行符\n CONVFMT:在awk中数值隐式转换为字符串时,将根据CONVFMT的格式按照sprintf()的方式自动转换为字符串。默认值为”%.6g OFMT:在print中,数值会根据OFMT的格式按照sprintf()的方式自动转换为字符串。默认值为”%.6g
第二类:携带信息的预约义变量
ARGC和ARGV:awk命令行参数的数量、命令参数的数组。 ARGIND:awk当前正在处理的文件在ARGV中的索引位置。因此,若是awk正在处理命令行参数中的某文件,则ARGV[ARGIND] == FILENAME为真 FILENAME:awk当前正在处理的文件(命令行中指定的文件),因此在BEGIN中该变量值为空 ENVIRON:保存了Shell的环境变量的数组。例如ENVIRON["HOME"]将返回当前用户的家目录 NR:当前已读总记录数,多个文件从不会重置为0,因此它是一直叠加的,能够直接修改NR,下次读取记录时将在此修改值上自增 FNR:当前正在读取文件的第几条记录,每次打开新文件会重置为0,能够直接修改FNR,下次读取记录时将在此修改值上自增 NF:当前记录的字段数, RT:在读取记录时真正的记录分隔符, RLENGTH:match()函数正则匹配成功时,所匹配到的字符串长度,若是匹配失败,该变量值为-1 RSTART:match()函数匹配成功时,其首字符的索引位置,若是匹配失败,该变量值为0 SUBSEP:arr[x,y]中下标分隔符构建成索引时对应的字符,默认值为\034,是一个不太可能出如今字符串中的不可打印字符。
一、$0,$1,$2,...,$NF
[root@lgh test]# awk '{print $0,$1,$2,$NF}' test.txt #输出整行,而后输出第一,第二,和最后一个字段的值 ID name gender age email phone ID name phone 1 zhangs female 34 aaa@163.com 13423394013 1 zhangs 13423394013
2 lisi male 45 abb@gmail.com 15608492523 2 lisi 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505 3 wmzi 18848796505
4 wangw female 31 acc@sohu.com 18848796506 4 wangw 18848796506
5 liub male 56 gdd@163.com 18848796507 5 liub 18848796507
6 zhangf female 34 adb@139.com 18848796573 6 zhangf 18848796573
7 guany male 56 eab@189.com 17048796508 7 guany 17048796508
8 zhaoy female 35 189@163.com 17058796503 8 zhaoy 17058796503
9 huangz male 65 dd@189.com 13648796593 9 huangz 13648796593
10 lvbu male 43 byy@sohu.com 18148796803 10 lvbu 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 11 sunwk 18148706803
二、RS、IGNORECASE
RS有两种状况:
RS为单个字符:直接使用该字符做为分隔符进行分割记录
RS为多个字符:将其当作正则表达式,只要匹配正则表达式的符号,都用来作分割记录,设置预约义变量INGORECASE为非零值,表示正则忽略大小写
[root@lgh test]# echo "bababaABAB" | awk 'BEGIN{IGNORECASE=1;RS="a+"}{print $0}' #正则忽略大小写切分读取 b b b B B [root@lgh test]# echo "bababaABAB" | awk 'BEGIN{IGNORECASE=0;RS="a+"}{print $0}' #正则不忽略大小写切分读取 b b b ABAB [root@lgh test]# echo "bababaABAB" | awk 'BEGIN{IGNORECASE=1;RS="a"}{print $0}' #非正则,IGNORECASE无效 b b b ABAB
三、分隔符FS、FIELDWIDTHS
[root@lgh test]# awk -F" +|@" '{print $1,$2,$3,$4,$5,$6,$7}' test.txt #正则,一个空格或者多个空格,或者@符进行分割 ID name gender age email phone 1 zhangs female 34 aaa 163.com 13423394013
2 lisi male 45 abb gmail.com 15608492523
3 wmzi female 61 ccc sohu.com 18848796505
4 wangw female 31 acc sohu.com 18848796506
5 liub male 56 gdd 163.com 18848796507
6 zhangf female 34 adb 139.com 18848796573
7 guany male 56 eab 189.com 17048796508
8 zhaoy female 35 189 163.com 17058796503
9 huangz male 65 dd 189.com 13648796593
10 lvbu male 43 byy sohu.com 18148796803
11 sunwk male 99 suk sohu.com 18148706803 [root@lgh test]# awk '{print $1,$2}' FS=":" /etc/passwd | head -2 #使用FS指定:为分割分 root x bin x [root@lgh test]# awk -F":" '{print $1,$2}' /etc/passwd | head -2 #使用-F指定:分隔符 root x bin x
预约义变量FIELDWIDTHS按字符宽度分割字段
FIELDWIDTHS="1 2 3 4" :表示第一个字段1个字符,第二个2个字符,第三个3个字符,第四个4个字符
[root@lgh test]# cat name.txt #文件内容 ID name gender age email phone 1 female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523 [root@lgh test]# awk '{print $2}' name.txt #获取第二列,其中female是第三列的内容 name female lisi [root@lgh test]# awk 'BEGIN{FIELDWIDTHS="8 8"}{print $2}' name.txt #正确的获取第二列 name lisi [root@lgh test]# echo 'bababaABAB' | awk 'BEGIN{FIELDWIDTHS="1 2 3 4"}{print $1,$2,$3,$4}' #使用指定字符长度分割 b ab aba ABAB
四、FS、OFS
FS是读取行时的字段分割,OFS是输出时的字段分隔符
[root@lgh test]# awk 'BEGIN{OFS="="}{print $1,$2}' test.txt ID=name 1=zhangs 2=lisi 3=wmzi 4=wangw 5=liub 6=zhangf 7=guany 8=zhaoy 9=huangz 10=lvbu 11=sunwk
[root@lgh test]# awk 'BEGIN{OFS="-"}{$1=$1;print $0}' test.txt #重组$0,修改$1,$2,...,$NF中的内容,以及增大或者减小NF的值,都会产生$0的重组 ID-name-gender-age-email-phone 1-zhangs-female-34-aaa@163.com-13423394013
2-lisi-male-45-abb@gmail.com-15608492523
3-wmzi-female-61-ccc@sohu.com-18848796505
4-wangw-female-31-acc@sohu.com-18848796506
5-liub-male-56-gdd@163.com-18848796507
6-zhangf-female-34-adb@139.com-18848796573
7-guany-male-56-eab@189.com-17048796508
8-zhaoy-female-35-189@163.com-17058796503
9-huangz-male-65-dd@189.com-13648796593
10-lvbu-male-43-byy@sohu.com-18148796803
11-sunwk-male-99-suk@sohu.com-18148706803
五、RS、ORS
RS是读取时的行分割,ORS是输出时的行分割
[root@lgh test]# echo -e "a\nb" |awk '{print $1}' #RS默认\n a b [root@lgh test]# echo -e "a\nb" |awk 'BEGIN{ORS="hello word"}{print $1}' #使用hello word代替\n进行输出 ahello wordbhello word
六、OFMT
变量OFMT(Output format)定义的格式按照sprintf()相同的方式进行格式化。OFMT默认值为%.6g,表示有效位(整数部分加小数部分)最多为6。
[root@lgh test]# awk 'BEGIN{OFMT="%.3f";print 3.141592678}' #会进行四舍五入
3.142 [root@lgh test]# awk 'BEGIN{print 3.141592678}'
3.14159
经常使用格式符: %c :将ASCII码转换为字符, %d :转为整数 %e :科学计数方法输出 %o :转为8进制输出 %s :转为字符串 %x :转16进制
七、NR、FNR
NR是该程序读取的记录数,FNR是程序读取某个文件的的记录数
[root@lgh test]# awk '{print NR,FNR,$0}' test.txt test.txt #NR一直递增,FNR根据文件从新设置1,而后递增 1 1 ID name gender age email phone 2 2 1 zhangs female 34 aaa@163.com 13423394013
3 3 2 lisi male 45 abb@gmail.com 15608492523
4 4 3 wmzi female 61 ccc@sohu.com 18848796505
5 5 4 wangw female 31 acc@sohu.com 18848796506
6 6 5 liub male 56 gdd@163.com 18848796507
7 7 6 zhangf female 34 adb@139.com 18848796573
8 8 7 guany male 56 eab@189.com 17048796508
9 9 8 zhaoy female 35 189@163.com 17058796503
10 10 9 huangz male 65 dd@189.com 13648796593
11 11 10 lvbu male 43 byy@sohu.com 18148796803
12 12 11 sunwk male 99 suk@sohu.com 18148706803
13 1 ID name gender age email phone 14 2 1 zhangs female 34 aaa@163.com 13423394013
15 3 2 lisi male 45 abb@gmail.com 15608492523
16 4 3 wmzi female 61 ccc@sohu.com 18848796505
17 5 4 wangw female 31 acc@sohu.com 18848796506
18 6 5 liub male 56 gdd@163.com 18848796507
19 7 6 zhangf female 34 adb@139.com 18848796573
20 8 7 guany male 56 eab@189.com 17048796508
21 9 8 zhaoy female 35 189@163.com 17058796503
22 10 9 huangz male 65 dd@189.com 13648796593
23 11 10 lvbu male 43 byy@sohu.com 18148796803
24 12 11 sunwk male 99 suk@sohu.com 18148706803
八、ARGS、ARGV
预约义变量ARGV是一个数组,包含了全部的命令行参数。该数组使用从0开始的数值做为索引。
预约义变量ARGC初始时是ARGV数组的长度,即命令行参数的数量。
ARGV数组的数量和ARGC的值只有在awk刚开始运行的时候是保证相等的。
[root@lgh test]# awk 'BEGIN{print ARGC;for(i in ARGV){print "ARGV[" i "]= " ARGV[i]}}' a b c 4 ARGV[0]= awk ARGV[1]= a ARGV[2]= b ARGV[3]= c
awk的全部代码(目前这么认为)都是写在语句块中的。
每一个语句块前面能够有pattern,好比:pattern1{action1}pattern2{action3;action4;...}
语句块可分为3类:BEGIN语句块、END语句块和main语句块。其中BEGIN语句块和END语句块都是的格式分别为BEGIN{...}和END{...},而main语句块是一种统称,它的pattern部分没有固定格式,也能够省略,main代码块是在读取文件的每一行的时候都执行的代码块。
BEGIN代码块:
在读取文件以前执行,且执行一次
在BEGIN代码块中,没法使用$0或其它一些特殊变量
main代码块:
读取文件时循环执行,(默认状况)每读取一行,就执行一次main代码块
main代码块可有多个
END代码块:
在读取文件完成以后执行,且执行一次
有END代码块,必有要读取的数据(能够是标准输入)
END代码块中可使用$0等一些特殊变量,只不过这些特殊变量保存的是最后一轮awk循环的数据
[root@lgh test]# awk 'BEGIN{print "hello word"}/^1/{print $0}END{print "END hello word"}' test.txt hello word 1 zhangs female 34 aaa@163.com 13423394013
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 END hello word
实例如上:begin和end均只输出一次,main代码中匹配1开头的行并输出
$ # $(2+2) ++ --
^ **
+ - ! # 一元运算符 * / %
+ - space # 这是字符链接操做 `12 " " 23` `12 " " -23` | |&
< > <= >= != == # 注意>便是大于号,也是print/printf的重定向符号 ~ !~
in
&&
||
?: = += -= *= /= %= ^=
&& 逻辑与 || 逻辑或 ! 逻辑取反 expr1 && expr2 # 若是expr1为假,则不用计算expr2 expr1 || expr2 # 若是expr1为真,则不用计算expr2 # 注: # 1. && ||会短路运算 # 2. !优先级高于&&和|| # 因此`! expr1 && expr2`等价于`(! expr1) && expr2`
输出格式:print elem1,elem2,elem3...
逗号分隔要打印的字段列表,各字段都会自动转换成字符串格式,而后经过预约义变量OFS值(其默认值为空格)链接各字段进行输出
在print输出时会自动在尾部加上输出记录分隔符,输出记录分隔符的预约义变量为ORS,其默认值为\n
sprintf()采用和printf相同的方式格式化字符串,可是它不会输出格式化后的字符串,而是返回格式化后的字符串。因此,能够将格式化后的字符串赋值给某个变量。
[root@lgh test]# awk 'BEGIN{var=sprintf("%.3f",3.141592678);print var}' #使用sprintf进行格式化复制变量,而后输出
3.142 [root@lgh test]# awk 'BEGIN{var=sprintf("%d",3.141592678);print var}'
3 [root@lgh test]# awk 'BEGIN{OFMT="%.3f";print 3.141592678}' #使用OFMT指定格式进行输出
3.142 [root@lgh test]# awk 'BEGIN{OFMT="%d";print 3.141592678}'
3
重定向:
>filename时,若是文件不存在,则建立,若是文件存在则首先截断。以后再输出到该文件时将再也不截断。
>>filename时,将追加数据,文件不存在时则建立。
awk中只要不close(),任何文件都只会在第一次使用时打开,以后都不会再从新打开。
[root@lgh test]# awk '{print $1,$2 > "name.txt"}' test.txt #重定向到name.txt文件 [root@lgh test]# cat name.txt ID name 1 zhangs 2 lisi 3 wmzi 4 wangw 5 liub 6 zhangf 7 guany 8 zhaoy 9 huangz 10 lvbu 11 sunwk
awk数组特性:
数组的访问和赋值都是经过制定下标就行赋值和访问,下标能够为整数,负数,字符串,小数
例如:
[root@lgh test]# cat a.awk { arr[i]="a" arr[-1]="b" print arr[i] print arr[-1] print length(arr) print arr[1] #输出不存在的数组下标内容 print "################" print length(arr) #长度+1 } [root@lgh test]# echo 0 | awk -f a.awk a b 2 ################ 3
数组遍历、删除、判读某key是否在arr中:
[root@lgh test]# cat a.awk { arr["x"]="a" arr[-1]="b" arr[4.5]=1 arr[4]=5
for(idx in arr){ #遍历 print arr[idx] } print "###############" delete arr[4] #删除元素,也能够删除整个数组delete arr for(idx in arr){ #遍历无序,与创建数组时输入的元素顺序不必定一致 print idx,arr[idx] } print "##############" print (-1 in arr) #判断key=-1,是否在数组中,是返回1,不是返回0 print (99 in arr) } [root@lgh test]# echo 0 | awk -f a.awk 5 b a 1 ############### -1 b x a 4.5 1 ############## 1
0
if判断:
if(condition){statement } if(condition){statement }else{statement } if(condition){statement }else if(condition){statement }else{statement }
三目运算
expr1 ? expr2 : expr3
switch选择:
switch (expression) { case value1|regex1 : statements1 case value2|regex2 : statements2 case value3|regex3 : statements3 ... [ default: statement ] }
[root@lgh test]# awk 'NR>1{$1>5? var="B": var="A";print $1,var}' test.txt 1 A 2 A 3 A 4 A 5 A 6 B 7 B 8 B 9 B 10 B 11 B [root@lgh test]# awk 'NR>1{if($1<5){print $1,"A"}else{print $1,"B"}}' test.txt 1 A 2 A 3 A 4 A 5 B 6 B 7 B 8 B 9 B 10 B 11 B
while和do…while
while(condition){ statements } do { statements } while(condition)
for循环
for (expr1; expr2; expr3) { statement } for (idx in array) { statement }
awk '{i=1;while(i<=NF){print $i;i++}}' test.txt awk '{for(i=1;i<=NF;i++) print $i}' test.txt
break:break可退出for、while、do…while、switch语句。
continue:continue可以让for、while、do…while进入下一轮循环。
next:next会在当前语句处当即中止后续操做,并读取下一行,进入循环顶部。
nextfile:nextfile会在当前语句处当即中止后续操做,并直接读取下一个文件,并进入循环顶部。
exit:直接退出awk程序,注意,END语句块也是exit操做的一部分,因此在BEGIN或main段中执行exit操做,也会执行END语句块。若是真的想直接退出整个awk,则能够先设置一个flag变量,而后在END语句块的开头检查这个变量再exit。
[root@lgh test]# awk 'NR==3{next}{print $0}' test.txt #匹配到了第3行,而后跳过 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 [root@lgh test]# awk 'NR==3{nextfile}{print $0}' test.txt test.txt #匹配到第3行,跳过该文件,执行下一个文件 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013 ID name gender age email phone 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
3 wmzi female 61 ccc@sohu.com 18848796505
4 wangw female 31 acc@sohu.com 18848796506
5 liub male 56 gdd@163.com 18848796507
6 zhangf female 34 adb@139.com 18848796573
7 guany male 56 eab@189.com 17048796508
8 zhaoy female 35 189@163.com 17058796503
9 huangz male 65 dd@189.com 13648796593
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803
[root@lgh test]# awk 'BEGIN{ print "hello work";exit}END{print "god job"}' #默认会执行END中的代码 hello work god job [root@lgh test]# awk 'BEGIN{ print "hello work";;exit flag=1}END{if(flag) exit ;print "god job"}' #使用flag跳出 hello work
awk中语句块没有做用域,都是全局变量(除非是函数中的形参)
变量的赋值:
能够x=y=z=5,等价于z=5 y=5 x=5 能够将赋值语句放在任意容许使用表达式的地方 x != (y = 1) awk 'BEGIN{print (a=4);print a}'
awk中声明变量的位置:
在BEGIN或main或END代码段中直接引用或赋值 使用-v var=val选项,可定义多个,必须放在awk代码的前面 它的变量声明早于BEGIN块 普通变量:awk -v age=123 'BEGIN{print age}' 使用shell变量赋值:awk -v age=$age 'BEGIN{print age}' 在awk代码后面使用var=val参数 它的变量声明在BEGIN以后 awk '{print n}' n=3 a.txt n=4 b.txt awk '{print $1}' FS=' ' a.txt FS=":" /etc/passwd 使用Shell变量赋值:awk '{print age}' age=$age a.txt
使用function关键字来定义函数:
function func_name([parameters]){
function_body
}
函数能够定义的位置:
awk '_ BEGIN{} _ MAIN{} _ END{} _' #能够定义在任何下划线的地方
[root@lgh test]# cat a.awk BEGIN{ f() } function f(){ print "自定义函数" } {}#main END{} [root@lgh test]# echo 0 | awk -f a.awk 自定义函数 [root@lgh test]# vim a.awk [root@lgh test]# cat a.awk function f(){ print "自定义函数" } BEGIN{ f() } {}#main END{} [root@lgh test]# echo 0 | awk -f a.awk 自定义函数 [root@lgh test]# vim a.awk [root@lgh test]# cat a.awk BEGIN{ f() } {}#main END{} function f(){ print "自定义函数" } [root@lgh test]# echo 0 | awk -f a.awk 自定义函数
带参数和return的自定义函数:
[root@lgh test]# cat a.awk BEGIN{ print f(1,2) } {}#main END{} function f(a,b){ print "自定义函数"
return a+b } [root@lgh test]# echo 0 | awk -f a.awk 自定义函数 3
参数的传递形式:
传递普通变量时,是按值拷贝传递
传递数组时,是按引用传递
awk变量做用域:
[root@lgh test]# cat a.awk BEGIN{ a=50 #全局 print a #50 print f(a,2) #42 print a #50 } {}#main END{} function f(a,b){ print "自定义函数" a=40 #覆盖了全局变量a print "局部",a return a+b #40+2 } [root@lgh test]# echo 0 | awk -f a.awk 50 自定义函数 局部 40
42
50
getline函数用于从文件、标准输入或管道中读取数据,并按状况设置变量的值。getline能够自动不断的加载下一行。若是能读取记录,则getline的返回值为1,遇到输入流的尾部时,返回值为0,不能读取记录(如文件没有读取权限、文件不存在)时,返回值为“-1"。
其中:
getline与netx的区别
getline:读取下一行以后,继续执行getline后面的代码
next:读取下一行,当即回头awk循环的头部,不会再执行next后面的代码
[root@lgh test]# awk '/^1/{print;getline;print}' test.txt #匹配1开头的行,在1开头的时候,获取到了下一行,也打印了出来 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 [root@lgh test]# awk '/^1/{print;getline;print;exit}' test.txt #执行了getline,print,而后exit了 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523 [root@lgh test]# awk '/^1/{print;if((getline var)<0)exit;print var}' test.txt #getline赋值给了var 1 zhangs female 34 aaa@163.com 13423394013
2 lisi male 45 abb@gmail.com 15608492523
10 lvbu male 43 byy@sohu.com 18148796803
11 sunwk male 99 suk@sohu.com 18148706803 [root@lgh test]# awk '/^1/{print;if((getline var)<0)exit;print $0}' test.txt #getline赋值给了var,可是没有设置$0 1 zhangs female 34 aaa@163.com 13423394013
1 zhangs female 34 aaa@163.com 13423394013
10 lvbu male 43 byy@sohu.com 18148796803
10 lvbu male 43 byy@sohu.com 18148796803
[root@lgh test]# awk '/^2/{while((getline var <"a.awk")>0)print var;close("a.awk")}' test.txt #匹配2开头的行,只有一行,因此后面只执行一次,把a.awk里面的内容赋值给var变量,而后输出 BEGIN{ a=50 print a print f(a,2) print a } {}#main END{} function f(a,b){ print "自定义函数" a=40 print "局部",a return a+b } [root@lgh test]# awk '/^2/{while((getline<"a.awk")>0){print};close("a.awk")}' test.txt #匹配2开头的行,只有一行,因此只执行一次,输出a.awk中的内容 BEGIN{ a=50 print a print f(a,2) print a } {}#main END{} function f(a,b){ print "自定义函数" a=40 print "局部",a return a+b }
[root@lgh test]# awk '/^2/{"date"|getline;print}' test.txt #使用linux的date命令,经过管道,使用getline读取 Tue Nov 24 19:44:28 CST 2020 [root@lgh test]# awk '/^2/{"date"|getline var ;print var}' test.txt Tue Nov 24 19:44:41 CST 2020 [root@lgh test]# awk '/^1/{"date"|getline var ;print var}' test.txt Tue Nov 24 19:44:48 CST 2020 Tue Nov 24 19:44:48 CST 2020 Tue Nov 24 19:44:48 CST 2020
awk虽然强大,可是有些数据仍然不方便处理,这时可将数据交给Shell命令去帮助处理,而后再从Shell命令的执行结果中取回处理后的数据继续awk处理。awk经过|&符号来支持coproc。
awk_print[f] "something" |& Shell_Cmd Shell_Cmd |& getline [var]
这表示awk经过print输出的数据将传递给Shell的命令Shell_Cmd去执行,而后awk再从Shell_Cmd的执行结果中取回Shell_Cmd产生的数据
[root@lgh test]# cat a.awk BEGIN{ CMD="sed -nr \"s/.*@(.*)$/\\1/p\""; #获取邮箱@符号后面的内容 } NR>1{ print $5; #输出邮箱名 print $5 |& CMD; #截取邮箱@符号后面的内容 close(CMD,"to"); CMD |& getline email_domain; #把邮箱@后面的内容赋值给变量email_domain close(CMD); print email_domain; #输出email_domain } [root@lgh test]# awk -f a.awk test.txt aaa@163.com 163.com abb@gmail.com gmail.com ccc@sohu.com sohu.com acc@sohu.com sohu.com gdd@163.com 163.com adb@139.com 139.com eab@189.com 189.com 189@163.com 163.com dd@189.com 189.com byy@sohu.com sohu.com suk@sohu.com sohu.com
index(str1,str2):返回子串str2在字符串str1中第一次出现的位置。若是没有指定str1,则返回0。 length(str1):返回字符串str1的长度。若是未给定str1,则表示计算"$0"的长度。 substr(str1,p):返回str1中从p位置开始的后缀字符串。 substr(str1,p,n):返回str1中从p位置开始,长度为n的子串。 match(str1,regexp):若是regexp能匹配str1,则返回匹配起始位置。不然返回0。它会设置内置变量RSTART和RLENGTH的值。 split(str1,array,sep):使用字段分隔符sep将str1分割到数组array中,并返回数组的元素个数。若是未指定sep则采用FS的值。所以该函数用于切分字段到数组中,下标从1开始。 sprintf(fmt,expr):根据printf的格式fmt,返回格式化后的expr。 sub(regexp,rep,str2):将str2中第一个被regexp匹配的字符串替换成rep,替换成功则返回1(表示替换了1次),不然返回0。注意是贪婪匹配。 sub(regexp,rep):将"$0"中第一个被regexp匹配的字符串替换成rep,替换成功则返回1,不然返回0。注意是贪婪匹配。 gsub(regexp,rep,str2):将str2中全部被regexp匹配的内容替换成rep,并返回替换的次数。 gsub(regexp,rep):将"$0"中全部被regexp匹配的内容替换成rep,并返回替换的次数。 toupper(str):将str转换成大写字母,并返回新串。 tolower(str):将str转换成小写字母,并返回新串。
int(expr) 截断为整数:int(123.45)和int("123abc")都返回123,int("a123")返回0 sqrt(expr) 返回平方根 rand() 返回[0,1)之间的随机数,默认使用srand(1)做为种子值 srand([expr]) 设置rand()种子值,省略参数时将取当前时间的epoch值(精确到秒的epoch)做为种子值
参考:
http://www.javashuo.com/article/p-bvyrznwq-br.html