写在前面:
博客书写牢记5W1H法则:What,Why,When,Where,Who,How。
本篇主要内容:
● awk
简介:
CentOS中所用的awk是指Gawk,即GNU AWK。是由Aho, Kernighan, and Weinberger三位开发的,是早起UNIX上awk的延伸。
awk工作模式:
awk是由主循环脚本和循环体前后脚本三部分组成的。
主循环:从文件第一行开始,对每一行进行处理操作,直到最后一行或用户手动终止(使用了exit命令)。
循环前:在脚本前添加BEGIN关键字,将在主循环开始前完成脚本内容的执行;
循环后:在脚本前添加END关键字,将在主循环结束后完成脚本内容的执行;
补充:awk脚本允许在脚本的任意位置添加 # + 注释内容。
使用格式:
awk [选项] 'PROGRAM' FILE ...
PROGRAM:PATTERN{ACTION STATEMENTS}
{}内多条语句用";"分隔
常用选项:
-f Program-file
--file Program-file
指定脚本文件
-F fs
--field-separator fs
指定域(列)分隔符,这里的分隔符可以是多个字符或PATTERN
-v var=val
--assign var=val
声明自定义变量或为内建变量赋值;也可以直接在{}中定义
-d[file]
--dump-variables[=file]
导出所有变量信息,省略file则使用缺省文件awkvars.out
内建变量:
NF:number of fields,当前行域(列)的数量
$0:当前行
$1:第一列
ARGC:arguments count.命令参数数量(包括awk本身以及后跟的文件)
ARGV:arguments array,数组,其中的元素是各命令参数。索引为从0到ARGC-1
ARGIND:the index in ARGV,当前awk正在处理的ARGV元素索引值。
FILENAME:当前处理的文件名。等同于ARGV[ARGIND]
FNR:number of input records by file,当前处理的行的行号,不同文件重新开始计数。
NR:number of input records,当前处理的行的行号,不同文件继续上一文件计数。
例:
[root@www ~]# head -2 /etc/passwd > passwd_head [root@www ~]# awk 'BEGIN{print ARGC}' passwd_head file 3 [root@www ~]# awk 'BEGIN{print ARGV[0]}' passwd_head file awk [root@www ~]# awk 'BEGIN{print ARGV[1]}' passwd_head file passwd_head [root@www ~]# awk 'BEGIN{print ARGV[2]}' passwd_head file file [root@www ~]# awk '{print FNR}' passwd_head file 1 2 1 2 3 4 [root@www ~]# awk '{print NR}' passwd_head file 1 2 3 4 5 6 [root@www ~]# awk '{print FILENAME}' passwd_head file passwd_head passwd_head file file file file [root@www ~]# awk '{print ARGV[ARGIND]}' passwd_head file passwd_head passwd_head file file file file
行分隔:
FS:input field sepatator,输入分隔符,可以是多个字符或PATTERN
如:FS="[[:space:]]+|:" 指定分隔符为多个空格或":"
OFS:output field seprator,输出分隔符
RS:input record separator,输入换行符
ORS:output record separator,输出换行符
FIELDWIDTHS:使用固定长度字符取每一列,而不再使用FS,使用空格分隔多个列宽
FPAT:fields pattern,指定匹配模式切割列,即能匹配到模式则当做一列
例:
[root@www ~]# cat file "01","1008","0","10080539" "01","1013","X","10080539" "03","1007","0","20110625" "03","1076","X","20110625" [root@www ~]# awk 'BEGIN{FS="[\",]"}{print $2,$5}' file 01 1008 01 1013 03 1007 03 1076 [root@www ~]# awk 'BEGIN{FIELDWIDTHS="1 2 3 4 3 1 3 8 1"}{print $2,$4}' file 01 1008 01 1013 03 1007 03 1076 [root@www ~]# awk 'BEGIN{FPAT="[0-9X]+"}{print $1,$2}' file 1008 1013 1007 1076
数组:
数组赋值:
ARR[INDEX]="" 支持关联数组
数组取值:
取数组所有元素:
for(INDEX in ARR) print ARR[INDEX]
判断是否存在索引的值"VALUE"
if(VALUE in ARR) print "OK"
ACTION:
print [item1,item2,...]
输出的变量不用加"$";
省略item则相当于print $0
printf
printf FORMAT,item1,item2,...
不会自动换行,可使用\n手动换行
FORMAT中需要分别指定每个item的格式占位符
格式占位符:
%s:显示字符串;
%d, %i: 显示十进制整数;
%f:显示为浮点数;
%c: 显示字符的ASCII码;
%e, %E: 科学计数法数值显示;
%g, %G:以科学计数法或浮点形式显示数值;
%u:无符号整数;
%%: 显示%自身;
修饰符:
m[.n]:m为数字,控制显示的宽度;n为数字,表示小数点后的精度;
-:左对齐。默认为右对齐
+:显示数字符号(即便是正数也要显示+)
例:
[root@www ~]# awk -F: '{printf "UserName:%s UID:%s\n",$1,$3}' passwd_head UserName:root UID:0 UserName:bin UID:1 [root@www ~]# awk -F: '{printf "UserName:%-4s UID:%s\n",$1,$3}' passwd_head UserName:root UID:0 UserName:bin UID:1
操作符:
算数运算:
+ - * / % ^ (幂运算)
-x (取负)
+x (转换为数值)
赋值:
= += -= *= /= %= ^=
++ --
比较操作符:
> >= < <= != ==
模式匹配:
~:VAR~PATTERN PATTERN能匹配到VAR中的字符串
!~:VAR!~PATTERN
函数调用:
function_name(arg1,arg2,...)
条件表达式:
selector?if-true-expression:if-false-expression
例:
#算数运算 [root@www ~]# awk 'BEGIN{i=1;j=2;i++;print i+j}' 4 #注意模式匹配格式/PATTERN/ [root@www ~]# echo "I am your apple." | awk '{$0~/apple/?yn="OK":yn="NO";print yn}' OK [root@www ~]# echo "I am your orage." | awk '{$0~/apple/?yn="OK":yn="NO";print yn}' NO #判断uid是否大于等于1000,大于等于1000则输出“用户名 is Login User”,否则输出“用户名 is System User” [root@www ~]# awk -F: '{$3>=100?usertype="is Login User":usertype="is System User";print $1,usertype}' /etc/passwd
PATTERN:
BEGIN
END
BEGINFILE
ENDFILE
/regular expression/ :正则表达式
relational expression :关系表达式,为真则后续操作执行,如==等
pattern && pattern
pattern || pattern
pattern ? pattern : pattern
(pattern)
! pattern
pattern1, pattern2
范围匹配,从匹配pattern1的行开始,到pattern2的行结束
例:
#输出文件的4-9行 [root@www ~]# cat -n /etc/passwd | awk '4<=NR && NR<=9{print $0}' [root@www ~]# cat -n /etc/passwd | awk '$1==4,$1==9{print $0}'
控制语句:
if (condition) statement [ else statement ]
while (condition) statement
do statement while (condition)
与while循环不同的是,至少循环一次
for (expr1; expr2; expr3) statement
for (var in array) statement
break
continue
delete array[index]
delete array
exit [ expression ]
{ statements }
switch (expression) {
case value|regex : statement
...
[ default: statement ]
}
例:
#使用if语句,输出默认shell为/bin/bash的用户信息
[root@www ~]# cat awk_program { FS=":"; if($NF=="/bin/bash") print $0 } [root@www ~]# awk -f awk_program /etc/passwd fred:x:1002:1002::/home/fred:/bin/bash storm:x:1003:1003::/home/storm:/bin/bash hadoop:x:1004:1004::/home/hadoop:/bin/bash archlinux:x:1005:1005::/users/archlinux:/bin/bash gentoo:x:3002:3002::/home/gentoo:/bin/bash
#使用awk显示磁盘使用率大于等于20%的磁盘信息
[root@www ~]# df -h | awk -F '[[:space:]]+|%' '/^\/dev/ {if($5>=20) print $0}' /dev/sda3 20G 14G 6.8G 67% /usr /dev/sda1 497M 191M 307M 39% /boot [root@www ~]# df -h | awk '/^\/dev/ {FS="[[:space:]]+|%";if($5>=20) print $0}' /dev/sda3 20G 14G 6.8G 67% /usr /dev/sda1 497M 191M 307M 39% /boot
#输出/etc/passwd文件,每10行添加一个页码
[root@www ~]# awk '{print $0}{if(NR%10==0)print "--",NR/10,"--------"}' /etc/passwd
#使用awk获取/etc/passwd文件的第一行,列出每个字段的字符数量
[root@www ~]# awk -F: 'NR==1{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/passwd root 4 x 1 0 1 0 1 0 /root 5 /bin/bash 9
#利用awk统计本机所有连接状态的连接数量
[root@www ~]# netstat -tan | awk '/^tcp\>/{stat[$6]++}END{for(s in stat) print s,stat[s]}' LISTEN 5 ESTABLISHED 2
#利用awk统计所有访问本机http服务的主机IP,并统计访问次数(提示,所有成功的访问都会被记录在/var/log/httpd/access_log文件中)
[root@www ~]# awk '{ips[$1]++}END{for(i in ips)print i,ips[i]}' /var/log/httpd/access_log 172.18.31.1 45 172.18.31.6 1 172.18.31.7 2
#利用awk统计本机中开机挂载的所有文件系统类型及数量
[root@www ~]# awk '/^UUID/{fstype[$3]++;}END{for(t in fstype)print t,fstype[t]}' /etc/fstab xfs 3
#使用awk统计一篇文章中的前10个高频字
[root@www ~]# awk -F '' '{for(i=1;i<=NF;i++)word[$i]++}END{for(w in word) print w,word[w]}' c_1118548704.htm | sort -rnk2 | head , 74 党 54 学 40 、 39 要 35 习 28 。 28 育 27 的 27 教 27
I/O控制
next
进入下一行的循环
nextfile
结束当前文件操作,从下一文件读取行并操作
例:
#输出uid为偶数的用户信息
[root@www ~]# awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd [root@www ~]# awk -F: '{if($3%2==0)print $1,$3}' /etc/passwd
内置函数:
int():截出数字
rand():随机数,0<=N<1
length([s]):获取字符串长度,如果s未给出,则获取$0的字符串长度
字符串处理:
sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容;
gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容;
split(s,a[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;
例:
#使用awk获取正在访问本机的IP并统计每个IP的连接数
[root@www ~]# netstat -tanp | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count)print i,count[i]}' 172.18.31.1 2 0.0.0.0 5