1.awk1:
1.awk基础
vawk [options] 'Pattern{Action}' file # 语法格式
echo ddd >> testd
awk '{print}' testd
awk '{print $5}' testd #代表输出第五列的参数,没有指定分隔符默认使用空格,-F制定分隔符
awk 'print $1,$2' test #输出第一列和第二列,逗号表示输出内容使用空格分开
2.awk模式
AWK 包含两种特殊的模式:BEGIN 和 END
BEGIN 模式指定了处理文本之前需要执行的操作:
END 模式指定了处理完所有行之后所需要执行的操作:
awk 'BEGIN{print "aaa", "bbb"}{print $1}END{"game over"}' # 表示在开始输出aaa bbb ,结束之后输出gameover,中间的就是处理的行
作用:可以用来添加表头和标题
3.awk分隔符
awk有哪些分隔符,awk的默认分割符是空格,但是,这样描述并不精确,因为,awk的分隔符还分为两种,"输入分隔符 FS" 和 "输出分隔符OFS"
# 输入
awk -F # '{print $1,$2}' test # 制定以#输入分割
awk -v FS='#' '{print $1,$2}' test # 制定以#输入分割
# 输出
awk -v OFS='+++' '{print $1,$2}' test # 制定以+++输出分割
awk '{print $1$2}' test # 不使用分隔符
awk '{print $1 $2}' 表示每行分割后,将第一列(第一个字段)和第二列(第二个字段)连接在一起输出。
awk '{print $1,$2}' 表示每行分割后,将第一列(第一个字段)和第二列(第二个字段)以输出分隔符隔开后显示。
4.变量
FS:输入字段分隔符, 默认为空白字符
awk -v FS='#' '{print $1,$2}' test # 制定以#输入分割
OFS:输出字段分隔符, 默认为空白字符
awk -v OFS='+++' '{print $1,$2}' test # 制定以+++输出分割
RS:输入记录分隔符(输入换行符), 指定输入时的换行符
我们不想以默认的"回车换行"作为"行分隔符",而是想使用空格作为所谓的行分隔符,也就是说,我们想让awk认为,每遇到一个空格,
就换行,换句话说,我们想让awk以为每次遇到一个空格就是新的一行
akw -v RS=' ' '{print NR,$0}'
ORS:输出记录分隔符(输出换行符),输出时用指定符号代替换行符
让awk认为,"+++"才是真正的输出行分隔符
awk -v ORS='+++' '{print NF,$0}' test1
awk -v ORS='+++' -v RS='' '{print NF,$0}' test1
NF:number of Field,当前行的字段的个数(即当前行被分割成了几列),字段数量
awk -v ORS='+++' -v RS='' '{print NF,$0}' test1
3 1 2 3
NR:行号,当前处理的文本行的行号。
awk '{print NR,NF}' test # 输出每一行的行号和列数
FNR:各文件分别计数的行号
awk '{print FNR,$0}' test test1 # 分别对每个文件的行数进行计数
FILENAME:当前文件名
awk '{print FILENAME,FNR,$0}' test test1
ARGC:命令行参数的个数
awk 'BEGIN{print "aaa",ARAV[0],ARGV[1],ARGV[2],ARGC}' test2 test1 # ARAV[0]表示awk本身,ARGC表示数组的长度
aaa awk test1 test2 3
ARGV:数组,保存的是命令行所给定的各参数
awk 'BEGIN{print "aaa",ARGV[1] }' test1 test2
aaa test1
awk 'BEGIN{print "aaa",ARGV[1],ARGV[2]}' test2 test1
aaa test2 test1
awk 'BEGIN{print "aaa",ARAV[0],ARGV[1],ARGV[2]}' test2 test1 # ARAV[0]表示awk本身
aaa awk test1 test2
5.自定义变量
方式一:
abc="6666"
awk -v myvar=$abc 'BEGIN{print myvar}'
666
awk -v myvar="testvar" 'BEGIN{print myvar}'
testvar
方式二:
awk -v 'BEGIN{myvar="testvar"; myvar2="testvar2";print myvar}'
testvar testvar2
6.awk格式化
awk 'BEGIN{print $1}' test1
abc
8yy
awk 'BEGIN{printf $1}' test1
abc 8yy
awk 'BEGIN{printf "%s
" , $1}' test1 # 需要使用逗号隔开
abc
8yy
printf "%s
" teststring
teststring
printf "%s
" 1 2 3 4 5
1
2
3
4
5
awk 'BEGIN{printf "%s
" , 1,2,3,4,5}'
1
awk 'BEGIN{printf "%s
" , $1}'
awk 'BEGIN{printf "%s
%s
" , 1,2,3,4,5}' # 必须与传入的参数数量相同
1
2
总结:
1)使用printf动作输出的文本不会换行,如果需要换行,可以在对应的"格式替换符"后加入"
"进行转义。
2)使用printf动作时,"指定的格式" 与 "被格式化的文本" 之间,需要用"逗号"隔开。
3)使用printf动作时,"格式"中的"格式替换符"必须与 "被格式化的文本" 一一对应。
cat test1
abc 123 iuy ddd
awk 'printf "第一列: %s 第二列: %s
" , $1,$2 ' test1
第一列: abc 第二列:123
cat test1
abc#123#iuy#ddd
awk -v FS='#' 'printf "第一列: %s 第二列: %s
" , $1,$2 ' test1
第一列: abc 第二列:123
awk -v FS='[ ]+' 'BEGIN{printf "%-10s %s
" , "用户名", "用户ID"}{printf "%-10s \%
" , $1,$2}' test1
用户名称 用户ID
abc 123
7.awk模式
cat test2
anc afds vasdf casdf dfdf
asf fd
fdsa fdf 56
awk 'NF==5 {print $0}' test2
anc afds vasdf casdf dfdf
awk 'NF>2 {print $0}' test2
anc afds vasdf casdf dfdf
asf fd
fdsa fdf 56
awk 'NF<4 {print $0}' test2
asf fd
fdsa fdf 56
awk '$1==asf {print $0}' test2
asf fd
关系运算符 |
含义 |
用法示例 |
< |
小于 |
x < y |
<= |
小于等于 |
x <= y |
== |
等于 |
x == y |
!= |
不等于 |
x != y |
>= |
大于等于 |
x >= y |
> |
大于 |
x > y |
~ |
与对应的正则匹配则为真 |
x ~ /正则/ |
!~ |
与对应的正则不匹配则为真 |
x !~ /正则/ |
1、空模式 # 不适用任何模式就是空模式
2、关系运算模式
3、正则模式
4、行范围模式
5、BEGIN/END模式
8.正则模式
awk '/^zsy/{print $0}' /etc/passwd # 找出以zsy开头的行
唯一的区别就是,在grep命令中,直接使用了正则表达式,而在awk命令中,正则表达式被放入了两个斜线中。
awk -v FS=':' 'BEGIN{printf "%-10s %s
" , "用户名", "用户ID"}/^zsy/{printf "%-10s %
" , $1,$2}' /etc/passwd
1、从/etc/passwd文件中找出符合条件的行(用户名以zsy开头的用户)。
2、找出符合条件的文本行以后,以":"作为分隔符,将文本行分段。
3、取出我们需要的字段,格式化输出。
4、结合BEGIN模式,输出一个格式化以后的文本,提高可读性。
awk '//bin/bash$/{print $0}' /etc/passwd # 找出以/bin/bash结尾的行
cat tests3
hey
heey
heeey
heeeey
awk -r '/he{2,3}/{print $0}' test3 # -r使用扩展正则
heey
heeey
9.awk行模式范围
cat -n test4
1 allent phillips
2 green lee
3 william aiden james lee
4 angle jack
5 tyler kevin
6 lucas thomas
7 kevin
akw '/lee/,/kevin/{print NR,$0}' test4 # 匹配从出现lee的行到kevin的行
2 green lee
3 william aiden james lee
4 angle jack
5 tyler kevin
awk 'NR=>2 && NR<=5{print NR,$0}' test4
2 green lee
3 william aiden james lee
4 angle jack
5 tyler kevin
关系运算符 |
含义 |
用法示例 |
< |
小于 |
x < y |
<= |
小于等于 |
x <= y |
== |
等于 |
x == y |
!= |
不等于 |
x != y |
>= |
大于等于 |
x >= y |
> |
大于 |
x > y |
~ |
与对应的正则匹配则为真 |
x ~ /正则/ |
!~ |
与对应的正则不匹配则为真 |
x !~ /正则/ |
cat test5
192.168.231.16
10.0.0.1
10.15.13.1
192.168.131.176
192.168.71.154
awk -r '$2~/192.168.[0-9]{1,3}.[0-9]{1,3}/{print $1,$2}' test5
192.168.231.16
192.168.131.176
192.168.71.154
10.awk动作
cat test6
he y
he ey
he eey
he eeey
awk -r '{print $0}{print $1}' test3 # 组合语句
he
y
he
ey
he
eey
he
eeey
11.akw条件语句
if语句:
awk -r '{print $0 ;print $1}' test3 # 组合语句 ,等价于上面
awk ' {if(NR==1){print $0}}' # 条件语句
awk '{if(NF==1){print $1} else{print $2}}' /etc/passwd
awk '{if(NF==1){print $1} else if(NF==2 && NF>3){print $0} else{print $2}}' /etc/passwd #多分支
循环语句:
awk 'BEGIN{ for(i=1;i,=6;i++){print i}}'
1
2
3
4
5
6
awk -v i=1 "BEGIn{ while(i<=5){print i;i++}}"
1
2
..
awk 'BEGIn{i=1;while(i<=5){print i;i++}}' # 同上
akw 'BEGIn{i=1;do{print "test"; i++} while(i<1)}'
test
akw 'BEGIn{do{print "test"; i++} while(i<5)}' #无论如何都执行一次都之后的语句
test
test
..
关键字:
continue的作用:跳出"当前"循环
break的作用:跳出"整个"循环
exit的作用:跳过awk执行语句,执行END中的内容
next的作用:跳过这行去执行接下来的行
awk 'BEGIN{for(i=0;i<6;i++){print i}}'
awk 'BEGIN{for(i=0;i<6;i++){if(i==3){continue};print i}}'
0
1
2
4
5
awk 'BEGIN{for(i=0;i<6;i++){if(i==3){break};print i}}'
0
1
2
# exit直接结束去执行END中的语句
akw 'BEGIn{i=1;do{print 1; exit;print 2}{print "fadsf"}END{print "over"}'
1
over
# 跳过第二行
awk '{if NR==2}{next}{print $0}' test6
12:awk数组:awk中的数组默认下标从1开始
awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; printhuluwa[1]}'
如果我们直接引用这个不存在的元素,awk会自动创建这个元素,并且默认为这个元素赋值为"空字符串";所以在akw中我们不能是用if(huluwa[5]="")进行判断.一个
元素是否为空,有可能它不存在,创建了一个.
awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; printhuluwa[4]}'
空
如何进行判断呢?
awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; if(6 in huluwa){print "6存在就打印出来"}}'
# 使用!取反
awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; if(!(6 in huluwa)){print "6存在就打印出来"}}'
# 关联数组
awk 'BEGIN{huluwa["一号"]="1";huluwa["二号"]="2";huluwa["三号"]="3" ; if(!("三号" in huluwa)){print "6存在就打印出来"}}'
# delete删除数组
awk 'BEGIN{huluwa["一号"]="1";huluwa["二号"]="2";huluwa["三号"]="3" ; print huluwa["一号"],delete huluwa;print huluwa["二号"]}'
1
空
空
awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; for(i=1;i<=3;i++){print i,huluwa[i]}}'
1
2
3
# 下表不规律的时候
awk 'BEGIN{huluwa[0]="1";huluwa[8]="2";huluwa[11]="3" ; for(i in huluwa){print i,huluwa[i]}}'
2
3
1
注意:在这种语法中,for循环中的变量"i"表示的是元素的下标,而并非表示元素的值,所以,如果想要输出元素的值,则需要使用"print 数组名[变量]"
注意:当数组中的下标为"字符串"时,元素值输出的顺序与元素在数组中的顺序不同,这是因为awk中的数组本质上是关联数组,所以默认打印出的元素是无序的。
这就是以数字作为下标的优势,因为第一种for循环语法中的变量"i"为数字,由于for循环的原因,"i"是按照顺序递增的,当"i"的值与下标的值相同时,我们
即可按照下标的顺序,输出对应元素的值,换句话说就是,我们是通过下标的顺序,输出对应元素值的顺序,也就是键值定位。但是,即使数组元素的下标为数字,如
果使用第二种for循环语法,也不能够按照顺序输出,示例如下。
awk 'BEGIN{huluwa[0]="1";huluwa[8]="2";huluwa[11]="3" ; for(i in huluwa){print i,huluwa[i]}}'
2
3
1
数值运算
awk 'BEGIN{ a=1 ;print a; a++ ;print a}'
1
2
awk 'BEGIN{ a="test" ;print a; a++ ;print a}' # 将字符串当做0相加,空字符串也一样
test
1
awk 'BEGIn{print array[x]; array[x]++;print array[x]}'
空
1
cat test7
18.43.31.4
183.65.31.4
18.22.31.4
18.43.31.4
awk '{count[$1]++} END{for (i in count){print i,count[i]}}' test7
18.43.31.4 2
183.65.31.4 1
18.22.31.4 1
cat -n test4
allent phillips
green lee
william aiden james lee
angle jack
tyler kevin
lucas thomas
kevin
awk '{for (i in NF){count[$i]++}} END{ for{j in count}{print j,count[j]}}' test4
jack 1
aiden 1
james 1
..
lee 2
..
13.awk 内置函数
awk 'BEGIN{srand(); print rand()}' # 生成随机数
0.134324
awk 'BEGIN{srand(); print int(rand()*100)}' # 生成100以内的随机数
0.134324
cat test8
allen fdsaf
awk "{ gsub("l","L",$1); print $1 }" test8 # 全局字符替换,制定列的全部
aLLen
awk "{ sub("l","L",$1); print $1 }" test8 # 单字符替换,每一行中的第一匹配到的
aLLen
awk '{for(i=1;i<=NF;i++){print $i,length($i)}}' test8 # 输出字符串长度
allen 5
fdsaf 5
awk '{for(i=1;i<=NF;i++){print $i,length()}}' test8 # 输出字符串长度,不指定列的时候,代表整行的长度
allen fdsaf 12
cat test9
allen phillips
green lee
william ken allen
akw '{print index($0,"lee")}' test9
0
7
0
在每一行中咋找字符串"Lee",如果Lee存在于当前行,则返回字符串Lee位于当前行的位置,如果Lee不存在于当前行,则返回0,表示当前行并不存在Lee,如上图所示,
第二行中包含Lee,而且Lee位于第二行的第7个字符的位置,所以返回数字7。
awk -v ts="一号:二号:三号" 'BEGIN{split(ts,huluwa,":")for (i in huluwa){print huluwa[i]}}' # 使用split生成数组
一号
二号
三号
被split函数分割后的数组的元素下标从1开始,不像其他语言中的数组下标是从0开始的,而且数组中元素输出的顺序可能与字符串中字符的顺序不同,
awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;for (i in t){print i, t[i]}}'
a 66
b 77
c 8
awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;asort(t); for (i in t){print i, t[i]}}'
1 3
2 66
3 77
数组中元素的值均为数字,但是下标为自定义的字符串,通过asort函数对数组排序后,再次输出数组中的元素时,已经按照元素的值的大小进行了排序,但是,数组
的下标也被重置为了纯数字,其实,asort还有一种用法,就是在对原数组元素值排序的同时,创建一个新的数组,将排序后的元素放置在新数组中,这样能够保持原数组不
做任何改变,我们只要打印新数组中的元素值,即可输出排序后的元素值
awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;asort(t, newt); for (i in t){print i, t[i]}}'
a 66
b 77
c 8
awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;asort(t, newt); for (i in newt){print i, newt[i]}}' # 生成新数组
1 3
2 66
3 77
awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8; len=asort(t, newt); for (i=1;i<=len;i++){print i, newt[i]}}' # 生成新数组,asort的返回值是数组的长度
1 3
2 66
3 77
使用asort 函数可以根据元素的值进行排序,而使用asorti 函数可以根据元素的下标进行排序。
awk 'BEGIN{t["f"]=66;t["b"]=77;t["e"]=8; len=asorti(t, newt); for (i=1;i<=len;i++){print i,newt[i]}}'
1 b
2 e
3 f
当数组的下标为字符串时,asorti 函数会根据原数组中的下标的字母顺序进行排序,并且将排序后的下标放置到一个新的数组中,并且asorti函数会返回新的数组的长度
awk 'BEGIN{t["f"]=66;t["b"]=77;t["e"]=8; len=asorti(t, newt); for (i in newt){print i,newt[i],t[newt[i]]}}'
1 b 77
2 e 8
3 f 66
14:awk三元运算符与打印奇偶行
我们可以判断用户的UID是否小于500,如果用户的UID大于500,则用户为普通用户,如果用户的UID小于500,则用户为系统用户。
awk -F: 'if {($3 < 500){print "系统用户"} else if ($3 > 500){print "普通用户"}}' /etc/passwd
awk -F: 'BEGIN{usertype=$3>500?"普通用户":"系统用户"; print $1,usertype}' /etc/passwd
条件 ? 结果1 : 结果2
awk -F : '{$3>500?a++;b++}END{ print a,b}' /etc/passwd
42 7 # 统计普通用户和系统用户数量
akw '1{print $0}' test3 == awk '1' test3 # 其中的1可以理解为一种模式,1表示为真
1 hey
2 heey
3 heeey
akw '0{print $0}' test3 == awk '0' test3 # 其中的0可以理解为一种模式,0表示为假,所以不输出匹配的东西
akw '!0{print $0}' test3 == awk '!0' test3 # 其中的0可以理解为一种模式,0表示为假,所以不输出匹配的东西,但是!表示取反,所以这个时候!0为真
1 hey
2 heey
3 heeey
awk 'i=!i' test3 # 指数出奇数行,第一i为空(假),取反之后为真,第二次i真,取反之后为假,以此类推,第三次i为第二次的假,取反之后为真
2 heey
1.cpu:
内置变量:
$0 表示显示整行
$NF表示当前行分割后的最后一列($0和$NF均为内置变量),NF表示有多少列,$NF表示最后一列,进行运算$(NF-1)倒数第二列
参考:
http://www.zsythink.net/?s=awk
https://blog.51cto.com/12758568/2122677
https://blog.csdn.net/rj042/article/details/72860177 awk引用外部变量