awk的运行方式
(1) awk命令行
(2) awk程序文件
awk –f /path/from/awk_script
(3) awk脚本
#!/bin/awk –f
基本用法:
gawk[OPTIONS] ‘program’ FILE1 FILE2……
program:PATTERN{ACTIONSTATEMENT}
选项:
-F[]:指明输入字段分隔符
-vVAR_NAME=VALUE:变量赋值
-f /PATH/FROM/AWK_SCRIPT:
1、awk的输出命令之一:print
用法:print item1,item2,……
item:
字符串:用引号引用
变量:显示变量的值
引用变量:直接使用变量名
数值:无需加引号
示例:字符串输出,向系统中用户问好
[[email protected] ~]# awk -F: ‘{print"hello",$1}‘ /etc/passwd hello root hello bin hello daemon hello adm
变量输出:
显示变量:定义变量为f1,值为1,然后输出f1就会输出变量的值也就是1
[[email protected] ~]# awk -F: -v f1=1 ‘{print f1}‘/etc/passwd 1 1 1 1
引用变量:使用$引用变量,就相当于输出$1,也就是第一段的内容
[[email protected] ~]# awk -F: -v f1=1 ‘{print $f1}‘ /etc/passwd root bin daemon adm
输出数值:
[[email protected] ~]# awk ‘{print 123}‘ /etc/passwd 123 123
要点:
(1) 各item直接需要使用逗号分割;而输出时的分隔符为默认空白字符;
示例:没有使用逗号,就会将两个值接连在一起
[[email protected] ~]# awk ‘{print "hello""world"}‘ /etc/passwd helloworld helloworld helloworld
(2) 输出的各item可以为字符串或数值、当前记录的字段($#)、变量或awk的表达式;数值会被隐式转换为字符串进行输出
(3) print后面的item省略时,相当于允许“print $0”,用于输出整行
(4) 输出空白字符:“print”
2、变量
2.1内置变量
FS:输入字段分隔符,默认为空白
-v FS=”[ ,:.]” #指定多个分隔符
示例:指定FS的值为“:”,分割符也就成为了“:”。效果和-F:一样
[[email protected] ~]# awk -v FS=":" ‘{print$1,$3}‘ /etc/passwd root 0 bin 1 daemon 2
指定多个分隔符:输出awk.txt文件的第三字段,但是第三字段的分割符分别是空白字符和逗号,这时可以将FS赋值为空白和逗号。
[[email protected] ~]# cat awk.txt This is the firsh line. Here you are. This is tomas,jason. [[email protected] ~]# awk -v FS="[ ,]"‘{print $3}‘ awk.txt the are. tomas
RS:输入时的行分隔符,默认为换行符
示例:指定行分割符为空白字符,那么出现空白字符就会换号。
[[email protected] ~]# awk -v RS=" " ‘{print$0}‘ awk.txt This is the firsh line. Here you are. This is tomas,jason.
OFS:输出时的字段分隔符,默认为空白
示例:指定输出时字段分隔符为“:”
[[email protected] ~]# awk -v FS=":" -v OFS=":" ‘{print $1,$3,$7}‘ /etc/passwd root:0:/bin/bash bin:1:/sbin/nologin daemon:2:/sbin/nologin
ORS:输出时的行分隔符,默认为换行符
[[email protected] ~]# awk -v RS=" " -v ORS=" " ‘{print $0}‘ awk.txt This is the firsh line. Here you are. This is tomas,jason. [[email protected] ~]# awk -v ORS=" "‘{print $0}‘ awk.txt This is the firsh line. Here you are. This istomas,jason.
NF:当前行的字段数
示例:显示每一行的字段数
[[email protected] ~]# awk ‘{print NF}‘ awk.txt 5 3 3
显示最后一个字段
[[email protected] ~]# awk ‘{print $NF}‘ awk.txt line. are. tomas,jason.
NR:行数
示例:如果指定一个文件就显示一个文件的行数,如果指定两个文件就显示两个文件的行数
[[email protected] ~]# awk ‘{print NR}‘ awk.txt 1 2 3 [[email protected] ~]# awk ‘{print NR}‘ awk.txt/etc/issue 1 2 3 4 5 6 7 8 9
FNR:行数,各文件单独计数
示例:各文件单独计数
[[email protected] ~]# awk ‘{print FNR}‘ awk.txt/etc/issue 1 2 3 1 2 3 4 5 6
FILENAME:当前文件的文件名
[[email protected] ~]# awk ‘{print FILENAME}‘ awk.txt/etc/issue awk.txt awk.txt awk.txt /etc/issue /etc/issue /etc/issue /etc/issue /etc/issue /etc/issue
ARGC:awk命令行中的参数个数
[[email protected] ~]# awk ‘{print ARGC}‘ awk.txt 2 2 2 [[email protected] ~]# awk ‘{print ARGC}‘ awk.txt/etc/issue 3 3 3 3
awk和文件名是参数
ARGV:数组,保存了命令行参数本身
示例:显示第一个参数和第二个参数
[[email protected] ~]# awk ‘{print ARGV[0]}‘ awk.txt awk awk awk [[email protected] ~]# awk ‘{print ARGV[1]}‘ awk.txt awk.txt awk.txt awk.txt
2.2自定义变量
(1) -v VAR_NAME=VALUE
变量名区分字符大小写
(2)在program中自定义变量
示例:在program中定义变量;定义的变量为f1=3,输出$f1就是输出第三字段
[[email protected] ~]# awk‘BEGIN{FS=":";f1=3}{print $f1}‘ /etc/passwd 0 1 2
3、printf命令
语法:printf FORMAT,item1,item2,……
要点:
(1) 必须提供FORMAT
(2) 与print语句不同,printf不会自动换行,需要显式指定换行符:\n
(3) FORMAT中需要分别为后面的每个item指定一个格式符,否则item则无法显示
格式符:都以%开头,后面跟单个字符
%c:显示字符ASCII码
%d,%i:显示为十进制整数
%e,%E:科学计数法显示数值
%f:显示浮点数
%g,%G:以科学计数法或浮点数格式显示数值
%s:显示字符串
%u:显示无符号整数
%%:显示百分号自身
示例:如输出%s,恰恰$1就是字符串类型所以会输出
[[email protected] ~]# awk -F: ‘{printf "This isuser:%s.\n",$1 }‘ /etc/passwd This is user:root. This is user:bin. This is user:daemon.
两个格式符一起输出
[[email protected] ~]# awk -F: ‘{printf "This isuser:%s,his UID is %d.\n",$1,$3 }‘ /etc/passwd This is user:root,his UID is 0. This is user:bin,his UID is 1. This is user:daemon,his UID is 2.
注意:格式会和对应的段进行匹配,匹配到了就会输出,如果输出的段没有匹配的格式是不会显示的,如下示例,只有两个格式,但是输出三个段,那么最后一个段不会显示
[[email protected] ~]# awk -F: ‘{printf "This isuser:%s,his UID is %d.\n",$1,$3,$7 }‘ /etc/passwd This is user:root,his UID is 0. This is user:bin,his UID is 1.
如果想显示第七段必须要给对应的格式符
[[email protected] ~]# awk -F: ‘{printf "This isuser %s, his UID is %d, his shell is %s.\n",$1,$3,$7}‘ /etc/passwd This is user root, his UID is 0, his shell is/bin/bash. This is user bin, his UID is 1, his shell is/sbin/nologin. This is user daemon, his UID is 2, his shell is/sbin/nologin
修饰符:
#[.#]:
左边的#:用于指定宽度
右边的#:显示精度
+:显示数值字符
-:左对齐,默认为右对其
示例:第一个字段占20各字符显示,第三个字段占20各字符左对齐显示
[[email protected] ~]# awk -F: ‘{printf"%20s:%-20d\n",$1,$3}‘ /etc/passwd root:0 bin:1 daemon:2
第一个字段和第三个字段分别占20各字符并且左对齐
[[email protected] ~]# awk -F: ‘{printf"%-20s:%-20d\n",$1,$3}‘ /etc/passwd root :0 bin :1 daemon :2
4、操作符
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 负值
+x: 转换为数值
字符操作符:没有操作符,就一个字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^=
++,--
比较操作符:
>, >=, <. <=, ==, !=
模式匹配操作符:
~:是否能由右侧指定的模式所匹配;
!~:是否不能由右侧指定模式所匹配
逻辑操作符:
&&:与运算
||:或运算
!:非运算
条件表达式:
selector?if-true-expression:if-false-expression
挑选器:如果为真运行:如果为假运行
函数调用:
function_name(argu1,argu2,...)
示例:如果用户id大于500,则输出common user如果小于500输出sysuseror admin
[[email protected] ~]# awk -F:‘{$3>=500?usertype="common user":usertype="sysuser oradmin";printf "%-15s:%s\n",$1,usertype}‘ /etc/passwd rpcuser :sysuser or admin nfsnobody :common user pulse :sysuser or admin sshd :sysuser or admin tcpdump :sysuser or admin centos :common user gentoo :common user
输出当前系统每个分区的空间使用情况
[[email protected] ~]# df -h | awk ‘{printf"%-25s:%-s\n",$1,$5}‘ Filesystem :Use% /dev/mapper/vg0-root :2% tmpfs :0% /dev/sda1 :16% /dev/mapper/vg0-usr :21% /dev/mapper/vg0-var :2%
5、PATTERN
(1) empty:空模式,匹配所有行
如:awk ‘{print $NF}‘ /etc/passwd就是空模式
(2) /Regular Expression/:仅将ACTION应用于能被Regular Expression所匹配到的行。
显示ab开头的用户名和uid
[[email protected] ~]# awk -F: ‘/^[ab]/{print $1,$3}‘/etc/passwd bin 1 adm 3 avahi-autoipd 170 abrt 173 apache 48
(3) Relational Expression:关系表达式,即结果为“真”、“假”的表达式,或者其结果类同于“真”或“假”的表达;一般来说,其结果为非0数值或非空字符串即可为“真”,否则,则类同为“假”。
显示出uid大于500的用户
[[email protected] ~]# awk -F: ‘$3>=500{print$1,$3}‘ /etc/passwd nfsnobody 65534 centos 500 gentoo 501
显示用户的shell为bash的用户
[[email protected] ~]# awk -F: ‘/bash$/{print $1,$7}‘/etc/passwd root /bin/bash centos /bin/bash gentoo /bin/bash
显示指定字段的指定内容:如显示用户为root的用户并输出
[[email protected] ~]# awk -F: ‘$1~/root/{print$1,$7}‘ /etc/passwd root /bin/bash
如果不添加指定字段匹配root会输出
[[email protected] ~]# awk -F: ‘/root/{print $1,$7}‘/etc/passwd root /bin/bash operator /sbin/nologin
(4) line ranges:行范围,类似与sed或vim中的地址方式
startline,endline
(5) BEGIN/END:两个特殊模式
BEGIN:在文件格式化操作开始之前事先执行的一次操作;通常用于输出表头或做出一个预处理操作;
END:在文件格式操作完成之后,命令退出之前执行的一次操作;通常用于输出表尾或做出清理操作;
示例:打印一个表头
[[email protected] ~]# awk -F: ‘BEGIN{printf"%-20s%s\n---------------------------\n","UserName","UserID"}{printf"%-20s:%-d\n",$1,$3}‘ /etc/passwd UserName UserID --------------------------- root :0 bin :1 daemon :2
输出表尾
[[email protected] ~]# awk -F: ‘BEGIN{printf"%-20s%s\n---------------------------\n","UserName","UserID"}{printf"%-20s:%-d\n",$1,$3}END{print "----------------\nend"}‘/etc/passwd centos :500 gentoo :501 zabbix :496 ---------------- end
BEGIN对变量赋值
[[email protected] ~]# awk‘BEGIN{FS=":"}{print $1,$3}‘ /etc/passwd root 0 bin 1 daemon 2
6、常用的ACTION
(1) Expressions:例如变量赋值
(2) Control statements:控制语句,如if,while等
(3) Compound statements:复合语句
(4) input statements
(5) output statements
7、控制语句
7.1 if-else
语法:
if (condition)statement [ else statement ]
if (condition){statements} [else {statements}]
示例:输出uid大于500的用户,单分支if实现
[[email protected] ~]# awk -F: ‘{if ($3>=500) print$1,$3}‘ /etc/passwd nfsnobody 65534 centos 500 gentoo 501
判断用户uid和gid是否相同,如果相同则输出用户名及uid和gid
[[email protected] ~]# awk -F: ‘{if ($3==$4) print$1,$3,$4}‘ /etc/passwd root 0 0 bin 1 1 daemon 2 2
判断rc.sysinit文件中,字段数大于6的行,并输出行的字段数和行的内容
[[email protected] ~]# awk ‘{if (NF>=6) printNF,$0}‘ /etc/rc.d/rc.sysinit 8 # /etc/rc.d/rc.sysinit - run once at boot time 9 # Taken in part from Miquel van Smoorenburg‘sbcheckrc. 6 if [ -f /etc/sysconfig/network ]; then
示例:判断用户uid是否大于500,如果大于500输出用户名跟is a common user,否则输出用户名根is a sysadmin or sysuser
[[email protected] ~]# awk -F: ‘{if ($3>=500){print$1,"is a common user"} else {print $1,"is a sysadmin orsysuser"}}‘ /etc/passwd nfsnobody is a common user pulse is a sysadmin or sysuser sshd is a sysadmin or sysuser tcpdump is a sysadmin or sysuser centos is a common user gentoo is a common user
7.2 while循环
语法:while (condition) statement
while(condition) {statements}
条件为“真”时循环,为“假”时退出循环;
使用场景:通常用于在当前行的各字段间进行循环;
示例:输出issue文件中字符个数大于6的字段
[[email protected] ~]# awk ‘{i=1;while(i<=NF){if(length($i)>=6){print $i};i++}}‘ /etc/issue CentOS release (Final) Kernel Education Learning Services
说明:length是awk的内置函数,是用来取字段长度的
7.3do-while循环
语法:do statement while (condition)
do {statements} while (condtion)
意义:至少执行一次循环体
7.4for循环
语法:for (expr1;expr2;expr3) statement
for(expr1;expr2;expr3) {statements}
for (variable assignment;codition;iteration process) {for-body}
示例:显示issue文件中字符数大于等于6个的字段
[[email protected] ~]# awk‘{for(i=1;i<=NF;i++){if(length($i)>=6)print$i}}‘ /etc/issue CentOS release (Final) Kernel Education Learning Services
第二种用法:用于遍历数组中的元素
for(var_name in array) {for-body}
比如:weekdays是一个数组
weekdays
weekdays[mon]="Monday"
weekdays[tue]="Tuesday"
...
for(i in weekdays):此时,i变量会遍历weekdays数组的每个索引,即mon, tue,而非元素的值“Monday”或"Tuesday"等;
要获取元素的值:weekdays[i]
7.5swtich语句
语法:switch (expression) {case VALUE or /REGEXP/: statement; ...;default: statementN}
类似与shell中的case
7.6break and continue
break [n]:退出当前循环,n是一个数字,用于指定退出几层循环
continue:提前结束本轮循环而进入下一轮
7.7next
提前结束对本行文件的处理,而提前进入下一行的处理操作;
示例:显示用户id为奇数行的用户名和id
[[email protected] ~]# awk -F: ‘{if($3%2==0)next;print $1,$3}‘ /etc/passwd bin 1 adm 3 sync 5
8、数组
关联数组:
index-expression:
可以使用任意字符;
如果某数组元素事先不存在,则在引用时,awk会自动创建此元素并将其值初始化为空串;
因此,若要判断数组中的某元素是否存在,要使用“index in array”的方式进行判断;
要遍历数组中的元素,则要使用for (var_name in array)的方式进行;此时,var_name会遍历array的每个索引,所以,要显示数组元素的值,要使用array[var_name]
weekdays
weekdays[mon]="Monday"
weekdays[tue]="Tuesday"
...
for (i in weekdays):此时,i变量会遍历weekdays数组的每个索引,即mon, tue,而非元素的值“Monday”或"Tuesday"等;
要获取元素的值:weekdays[i]
注意:awk的数组下标从1开始编号
示例:统计count.txt文件中所有行,每个单词出现的次数
[[email protected] ~]# cat count.txt How are you? How old are you? What are you doing? [[email protected] ~]# awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(j in count) {print j,count[j]}}‘ /root/count.txt are 3 What 1 How 2 doing? 1 old 1 you? 2 you 1
for(i=1;i<=NF;i++):遍历所有字段
{count[$i]++}:将字段遍历结果赋值给数组,$i是数组的下标,遍历一边$i就加1
END{ }:循环数组显示统计结果
for(j in count):使用变量j遍历count数组的每一个下标
print j:输出单词名字
count[j]:输出单词出现的数量,由于每次遍历count数组出现相同的单词j就会加1,直到最后匹配不到位置,j最后的值就是单词出现的次数
单独统计每一行单词出现个数
[[email protected] ~]# awk ‘{for(i=1;i<=NF;i++){count[$i]++};for(j in count) {print j,count[j]};delete count}‘ /root/count.txt are 2 How 2 old 1 you? 2 are 1 What 1 doing? 1 you 1
delete count:每一行统计完成之后置空,数组
统计tcp连接状态
[[email protected] ~]# ss -tan | awk‘!/^State/{state[$1]++}END{for(i in state)print i,state[i]}‘ ESTAB 1 LISTEN 12
!/^State:去除第一行显示
{state[$1]++}:设置数组
for(i in state)print i,state[i]:循环数组,打印数组
统计web日志文件ip资源访问次数
[[email protected] ~]# awk ‘{ip[$1]++}END{for(i in ip)print i,ip[i]}‘ /var/log/httpd/access_log 172.16.4.230 24 172.16.4.136 4
{ip[$1]++}:循环ip段
for(i in ip):将ip段的值(ip地址)赋值给变量i
print i,ip[i]}:打印ip地址和输出ip的长度
9、函数
9.1内建函数
数值处理:
rand():返回0至1之间的一个随机数;
[[email protected] ~]# awk ‘BEGIN{print rand()}‘ 0.237788
字符串处理:
length([s]):返回指定的字符串的长度;
[[email protected] ~]# awk ‘BEGIN{printlength("hello world")}‘ 11
sub(r,s[,t]):基于r所表示的模式来匹配字符串t中的内容,将其第一次被匹配到的内容替换为s所表示的字符串;
[[email protected] ~]# cat count.txt How are you? How old are you? What are you doing? [[email protected] ~]# awk‘{sub("are","ARE,$0");print $0}‘ count.txt How ARE,$0 you? How old are you? What ARE,$0 you doing?
gsub(r,s[,t]):基于r所表示的模式来匹配字符串t中的内容,将其所有被匹配到的内容均替换为s所表示的字符串;
split(s,a[,r]):以r为分隔符去切割字符串s,并将切割后的结果保存至a表示的数组中;
取用户名:将“:”定为分隔符,对整个行进行切割,将结果赋值给userinfo,最后输出userinfo的第一个值
[[email protected] ~]# awk‘{split($0,userinfo,":");print userinfo[1]}‘ /etc/passwd root bin daemon
substr(s,i[,n]):从s所表示的字符串中取子串,取法:从i表示的位置开始,取n个字符;
时间类的函数:
systime():取时间戳;
位运算函数:
and(v1,va2):
9.2 自定义函数
functionf_name(p,q)
{
...
}