Linux中awk的使⽤⽅法详解
在学习awk之前我们应该都学过sed,grep,tr,cut等等命令,这些命令都是为了⽅便我们对Linux下⽂本和数据的处理,但是我们会发现很多时候这些命令并不能⼀下⼦就完全解决我们的需求,很多时候我们都需要使⽤管道符结合这些命令来使⽤,今天我就给⼤家介绍⼀个命令awk,他就能很好的解决我们对⽂本和数据处理的需求,使我们⼀条命令就解决很多问题。
⼀、awk命令简介
awk被称为⽂本处理三剑客之⼀,其名称得⾃于它的创始⼈ Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓⽒的⾸个字母。实际上 AWK 的确拥有⾃⼰的语⾔: AWK 程序设计语⾔,三位创建者已将它正式定义为“样式扫描和处理语⾔”。它允许您创建简短的程序,这些程序读取输⼊⽂件、为数据排序、处理数据、对输⼊执⾏计算以及⽣成报表,还有⽆数其他的功能。
所以说awk是⼀个强⼤的⽂本分析⼯具,相对于grep的查,sed的编辑,awk在其对数据分析并⽣成报告时,显得尤为强⼤。简单来说awk就是把⽂件逐⾏的读⼊,以空格为默认分隔符将每⾏切⽚,切开的部分再进⾏各种分析处理。
⼆、awk命令格式及选项
语法形式
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
常⽤命令选项
-F fs fs指定输⼊分隔符,fs可以是字符串或正则表达式,如-F:
-v var=value 赋值⼀个⽤户定义变量,将外部变量传递给awk
-f scripfile 从脚本⽂件中读取awk命令
-m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最⼤块数⽬;-mr选项限制记录的最⼤数⽬。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适⽤。
三、awk的原理
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
第⼀步:执⾏BEGIN{ commands }语句块中的语句;
第⼆步:从⽂件或标准输⼊(stdin)读取⼀⾏,然后执⾏pattern{ commands }语句块,它逐⾏扫描⽂件,从第⼀⾏到最后⼀⾏重复这个过程,直到⽂件全部被读取完毕。
第三步:当读⾄输⼊流末尾时,执⾏END{ commands }语句块。
BEGIN语句块在awk开始从输⼊流中读取⾏之前被执⾏,这是⼀个可选的语句块,⽐如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块在awk从输⼊流中读取完所有的⾏之后即被执⾏,⽐如打印所有⾏的分析结果这类信息汇总都是在END语句块中完成,它也是⼀个可选语句块。
pattern语句块中的通⽤命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执⾏{ print },即打印每⼀个读取到的⾏,awk读取的每⼀⾏都会执⾏该语句块。
四、awk 基本⽤法
awk的调⽤有三种⽅式
1.命令⾏⽅式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的⽂件。
在awk中,⽂件的每⼀⾏中,由域分隔符分开的每⼀项称为⼀个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
2.shell脚本⽅式
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
⼀个awk脚本通常由:BEGIN语句块、能够使⽤模式匹配的通⽤语句块、END语句块3部分组成,这三个部分是可选的。任意⼀个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中,例如:awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename
awk "BEGIN{ i=0 } { i++ } END{ print i }" filename
3.将所有的awk命令插⼊⼀个单独⽂件,然后调⽤
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上⾯的命令⾏⽅式是⼀样的。
我们通过⼏个简单的⽰例来进⼀步了解awk的⽤法
[root@localhost ~]# awk '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
.........................................................................
[root@localhost ~]# echo 123|awk '{print "hello,awk"}'
hello,awk
[root@localhost ~]# awk '{print "hi"}' /etc/passwd
hi
hi
hi
hi
hi
hi
hi
hi
hi
.........................................................................
我们指定/etc/passwd作为输出⽂件,执⾏awk时,它就会依次对/etc/passwd中的每⼀⾏执⾏print命令。
awk⼯作流程是这样的:读⼊有'\n'换⾏符分割的⼀条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表⽰所有域,$1表⽰第⼀个域,$n表⽰第n个域。默认域分隔符是"空⽩键" 或 "[tab]键",所以$1表⽰登录⽤户,$3表⽰登录⽤户ip,以此类推。如
打印/etc/passwd下所有的⽤户名
[root@localhost ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm ........................................................................
打印/etc/passwd下所有的⽤户名及UID
[root@localhost ~]# awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2 ........................................................................
以username: XXX uid: XXX格式输出
[root@localhost ~]# awk -F: '{print "username: " $1 "\t\tuid: "$3}' /etc/passwd
username: root uid: 0
username: bin uid: 1
username: daemon uid: 2
........................................................................
五、awk内置变量
变量描述
\$n当前记录的第n个字段,字段间由FS分隔
\$0完整的输⼊记录
ARGC命令⾏参数的数⽬
ARGIND命令⾏中当前⽂件的位置(从0开始算)
ARGV包含命令⾏参数的数组
CONVFMT数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
ERRNO最后⼀个系统错误的描述
FIELDWIDTHS字段宽度列表(⽤空格键分隔)
FILENAME当前⽂件名
FNR各⽂件分别计数的⾏号
FS字段分隔符(默认是任何空格)
IGNORECASE如果为真,则进⾏忽略⼤⼩写的匹配
NF⼀条记录的字段的数⽬
NR已经读出的记录数,就是⾏号,从1开始
OFMT数字的输出格式(默认值是%.6g)
OFS输出记录分隔符(输出换⾏符),输出时⽤指定的符号代替换⾏符
ORS输出记录分隔符(默认值是⼀个换⾏符)
RLENGTH由match函数所匹配的字符串的长度
RS记录分隔符(默认是⼀个换⾏符)
RSTART由match函数所匹配的字符串的第⼀个位置
SUBSEP数组下标分隔符(默认值是/034)
⽰例
[root@localhost ~]# echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print "Line No:"NR", No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3}'
Line No:1, No of fields:3 $0=line1 f2 f3 $1=line1 $2=f2 $3=f3
Line No:2, No of fields:3 $0=line2 f4 f5 $1=line2 $2=f4 $3=f5
Line No:3, No of fields:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7
使⽤print $NF可以打印出⼀⾏中的最后⼀个字段,使⽤$(NF-1)则是打印倒数第⼆个字段,其他以此类推:
[root@localhost ~]# echo -e "line1 f2 f3\n line2 f4 f5" | awk '{print $NF}'
f3
f5
[root@localhost ~]# echo -e "line1 f2 f3\n line2 f4 f5" | awk '{print $(NF-1)}'
f2
f4
统计/etc/passwd:⽂件名,每⾏的⾏号,每⾏的列数,对应的完整⾏内容:
[root@localhost ~]# awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
统计/etc/passwd⽂件中的命令⾏参数ARGC,⽂件⾏号FNR,字段分隔符FS,⼀条记录的字段数⽬NF,已经读出的记录数(默认是⾏号)NR
[root@localhost ~]# awk -F: 'BEGIN{printf "%4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FN
R","FS","NF","NR";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR}' /etc/passwd FILENAME ARGC FNR FS NF NR
---------------------------------------------
/etc/passwd 2 1 : 7 1
/etc/passwd 2 2 : 7 2
/etc/passwd 2 3 : 7 3
六、awk⾼级⽤法
1.awk赋值运算
赋值语句运算符:= += -= *= /= %= ^= **=
例如:a+=5;等价于a=a+5
[root@localhost ~]# awk 'BEGIN{a=5;a+=5;print a}'
10linux所有命令都无法使用
2.awk正则运算
输出包含有root的⾏,并打印⽤户名和UID及原⾏内容
[root@localhost ~]# awk -F: '/root/ {print $1,$3,$0}' /etc/passwd
root 0 root:x:0:0:root:/root:/bin/bash
operator 11 operator:x:11:0:operator:/root:/sbin/nologin
我们发现到了两⾏,如果我们想root开头的⾏就要这样写:awk -F: '/^root/' /etc/passwd
3.awk三⽬运算
[root@localhost ~]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'
ok
[root@localhost ~]# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'
err
三⽬运算其实就是⼀个判断运算,如果为真则输出?后的内容,如果为假则输出:后的内容
4.awk的循环运⽤
if语句运⽤
[root@localhost ~]# awk 'BEGIN{ test=100;if(test>90){ print "vear good";} else{print "no pass";}}'
vear good
每条命令后⽤;结尾
while循环运⽤
计算从1累加到100的值
[root@localhost ~]# awk 'BEGIN{test=100;num=0;while(i<=test){num+=i; i++;}print num;}'
5050
for循环的运⽤
[root@localhost ~]# awk 'BEGIN{test=0;for(i=0;i<=100;i++){test+=i;}print test;}'
5050
do循环的运⽤
[root@localhost ~]# awk 'BEGIN{test=0;i=0;do{test+=i;i++}while(i<=100)print test;}'
5050
5.awk的数组运⽤
数组是awk的灵魂,处理⽂本中最不能少的就是它的数组处理。因为数组索引(下标)可以是数字和字符串在awk中数组叫做关联数组(associative arrays)。awk 中的数组不必提前声明,也不必声明⼤⼩。数组元素⽤0或空字符串来初始化,这根据上下⽂⽽定。⼀般⽽⾔,awk中的数组⽤来从记录中收集信息,可以⽤于计算总和、统计单词以及跟踪模板被匹配的次数等等。
显⽰/etc/passwd的账户
awk -F: 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
0 root
1 bin
2 daemon
3 adm
4 lp
5 sync
........................................................................
6.awk字符串函数的运⽤
函数名描述
sub 匹配记录中最⼤、最靠左边的⼦字符串的正则表达式,并⽤替换字符串替换这些字符串。如果没有指定⽬标字符串就默认使⽤整个记录。替换只发⽣在第⼀次匹配的时候
sub (regular expression, substitution string):
sub (regular expression, substitution string, target string)
实例:
awk '{ sub(/test/, "mytest"); print }' testfile
awk '{ sub(/test/, "mytest"); $1}; print }' testfile
第⼀个例⼦在整个记录中匹配,替换只发⽣在第⼀次匹配发⽣的时候。如要在整个⽂件中进⾏匹配需要⽤到gsub
第⼆个例⼦在整个记录的第⼀个域中进⾏匹配,替换只发⽣在第⼀次匹配发⽣的时候。
gsub 整个⽂档中进⾏匹配
gsub (regular expression, substitution string)
gsub (regular expression, substitution string, target string)
实例:
awk '{ gsub(/test/, "mytest"); print }' testfile
awk '{ gsub(/test/, "mytest" , $1) }; print }' testfile
第⼀个例⼦在整个⽂档中匹配test,匹配的都被替换成mytest。
第⼆个例⼦在整个⽂档的第⼀个域中匹配,所有匹配的都被替换成mytest。
index 返回⼦字符串第⼀次被匹配的位置,偏移量从位置1开始
index(string, substring)
实例:
awk '{ print index("test", "mytest") }' testfile
实例返回test在mytest的位置,结果应该是3。
substr 返回从位置1开始的⼦字符串,如果指定长度超过实际长度,就返回整个字符串
substr( string, starting position )
substr( string, starting position, length of string )
实例:
awk '{ print substr( "hello world", 7,11 ) }'
上例截取了world⼦字符串。
split 可按给定的分隔符把字符串分割为⼀个数组。如果分隔符没提供,则按当前FS值进⾏分割
split( string, array, field separator )
split( string, array )
实例:
awk '{ split( "20:18:00", time, ":" ); print time[2] }'
上例把时间按冒号分割到time数组内,并显⽰第⼆个数组元素18。
length 返回记录的字符数
length( string )
length
实例:
awk '{ print length( "test" ) }'
awk '{ print length }' testfile
第⼀个实例返回test字符串的长度。
第⼆个实例返回testfile⽂件中第条记录的字符数。
match 返回在字符串中正则表达式位置的索引,如果不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中⼦字符串的开始位置,RLENGTH为到⼦字符串末尾的字符个数。
substr可利于这些变量来截取字符串
match( string, regular expression )
实例:
awk '{start=match("this is a test",/[a-z]+$/); print start}'
awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'
第⼀个实例打印以连续⼩写字符结尾的开始位置,这⾥是11。
第⼆个实例还打印RSTART和RLENGTH变量,这⾥是11(start),11(RSTART),4(RLENGTH)。toupper和tolower 可⽤于字符串⼤⼩间的转换,该功能只在gawk中有效
toupper( string )
tolower( string )
实例:
awk '{ print toupper("test"), tolower("TEST") }'
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论