Shell编程之---awk命令详解


awk编程
awk是一种编程语言。gawk、是最新版本,当前的linux版本用的都是gawk
awk是gawk的软链接

awk工作原理

BEGIN #在未读取文件行之前执行
主输入循环 (main input loop),反复执行,直到终止条件触发
END #在读取文件行完毕后执行


awk的三种调用方法
1、在shell命令行输入命令调用awk
#awk [-f 域分隔符] 'awk cmd' file

2、在awk程序段插入脚本文件,然后通过awk命令调用他
#awk -f 'awk.sh' file

3、直接调用awk脚本
#./awk file
=====================================================
awk模式匹配
任何awk语句都由模式(pattern)和动作(action)组成
模式是一组用于测试输入行是否需要执行动作的规则(模式决定动作何时触发和触发事件)
动作是包含语句、函数和表达式的执行过程 (执行对输入行的处理)

在test文件中一旦有空行,则打印出来"This is a empty line!!!"
#awk '/^$/{print "This is a empty line!!!"}' test
=====================================================
记录和域

awk将每个输入文件行定义为记录,行中的每个字符串定义为域,分隔域的符号叫做域分隔符

vim student

Li Hao njue 025-83481010
Zhang Ju nju 025-83466534
Wang Bin seu 025-83494883
Zhu Lin njupt 025-83680010


按顺序打印出student文件中的2、1、4、3域
#awk '{print $2,$1,$4,$3}' student

打印出student中所有的域
#awk '{print $0}' student

根据运算表达式列出第三个域的值
#awk 'BEGIN {one=1;two=2}{print $(one+two)}' student

以tab键位分隔符打印出student文件中第三个域
#awk 'BEGIN {FS="\t"} {print $3}' student

Li Hao,njue,025-83481010
Zhang Ju,nju,025-83466534
Wang Bin,seu,025-83494883
Zhu Lin,njupt,025-83680010

以逗号为域分隔符打印出所有的域的内容
#awk 'BEGIN {FS=","} {print $0}' student

以逗号为域分隔符打印出1、3域的内容
#awk 'BEGIN {FS=","} {print $1,$3}' student

abc d #中间两个tab
abc d #中间一个tab

打印出第一个域和d(两种方式)
#awk 'BEGIN {FS="\t\t"} {print $1,$2}' xx
#awk 'BEGIN {FS="\t"} {print $1,$3}' xx

打印出第一个域和上面的d
#awk 'BEGIN {FS="\t"} {print $1,$2}' xx

===============================================================
关系运算符
< #小于
> #大于
<= #小于等于
>= #大于等于
== #等于
!= #不等于
~ #匹配正则表达式
!~ #不匹配正则表达式

在/etc/passwd文件中打印出第一个域匹配于root的内容
#awk 'BEGIN {FS=":"} $1~/root/' /etc/passwd

在/etc/passwd文件中打印出全部域匹配于root的内容
#awk 'BEGIN {FS=":"} $0~/root/' /etc/passwd

在/etc/passwd文件中打印出全部域中不匹配nologin的内容
#awk 'BEGIN {FS=":"} $0!~/nologin/' /etc/passwd

在/etc/passwd文件中判断,如果UID小于GID,那么输出所有匹配的值
#awk 'BEGIN {FS=":"} {if($3<$4) print $0}' /etc/passwd

在/etc/passwd文件中判断,如果UID大于等于GID,那么输出所有匹配的值
#awk 'BEGIN {FS=":"} {if($3>=$4) print $0}' /etc/passwd

===============================================================
布尔运算符
|| #逻辑或
&& #逻辑与
! #逻辑非

打印出/etc/passwd文件中UID等于10或者GID等于10的行
#awk 'BEGIN {FS=":"} {if($3==10||$4==10) print $0}' /etc/passwd

打印出/etc/passwd文件中UID等于GID,并且登录shell都相同的匹配信息
#awk 'BEGIN {FS=":"} {OFS=":"} {if($3==$4&&$7="/sbin/nologin") print $0}' /etc/passwd

打印出/etc/passwd文件中UID匹配于10或GID匹配于10的匹配信息
#awk 'BEGIN {FS=":"} {if($3~10||$4~10) print $0}' /etc/passwd

================================================================
表达式 awk表达式用于存储、操作和获取数据,一个awk表达式可由数值,字符常量,变量,操作符,函数和正则组成
+ #加
- #减
* #乘
/ #除
% #模
^或** #乘方
++x #在返回x值之前,x变量加1
x++ #在返回x值之后,x变量加1

使用x+=1来列出文件test中的空行的行数
#awk '/^$/ {print x+=1}' test

第1行为0,然后递归+1列出test文件中的空行行数
#awk '/^$/{print x++}' test

第1行为1,然后递归+1列出test文件中的空行行数
#awk '/^$/{print ++x}' test

实例
Li hao,njue,025-83481010,85,92,78,94,88
Zhang Ju,nju ,025-83466534,89,90,75,90,86
Wang Bin, seu,025-83494883,84,88,80,92,84
Zhu Lin,njupt,025-83680010,98,78,81,87,76

求出文件student文件中学生的平均值
#awk 'BEGIN {FS=","} {total=$4+$5+$6+$7+$8} {avg=total/5} {print $1,avg}' student

================================================================
系统变量:awk定义了很多内建变量用于设置环境变量信息,我们称它为系统变量,这些系统变量分为两种
1、用于改变awk的默认值,如域分隔符
2、用于定义系统值,在处理文件时可以读取这些系统值,如记录中域数量,当前记录数,当前文件名,awk动态改变第二种系统变量的值

awk环境变量及其意义
#n #当前记录的第n个域,域间由FS分割
#0 #记录的所有域
ARGC #命令行参数的数量
ARGIND #命令行中当前文件的位置(以0开始标号)
ARGV #命令行参数的数组
CONVFMT #数字转换格式
ENVIRON #环境变量关联数组
ERRNO #最后一个系统错误的描述
FILEDWIDTHS #字段宽度列表,以空格键分隔
FILENAME #当前文件名
FNR #浏览文件的记录数
FS #字段分隔符,默认是空格键
IGONRECASE #布尔变量,如果为真,则进行忽略大小写的匹配
NF #当前记录中的域数量
NR #当前记录数
OFMT #数字的输出格式
OFS #输出域分隔符,默认是空格键
ORS #输出记录分隔符,默认是换行符
RLENGTH #由match函数所匹配的字符串长度
RS #记录分隔符,默认是空格键
RSTART #由match函数所匹配的字符串的第1个位置
SUBSEP #数组下标分隔符,默认值是\034

输出文件student,并在最前面加入 当前记录数,当前记录中域数量,在文件底部输出文件名

#awk 'BEGIN {FS=","} {print NR,NF,$0} END {print FILENAME}' student

====================================================================
格式化输出 awk借鉴了C语言的语法,定义了printf输出语句,规定输出的格式
printf (格式控制符,参数)

printf语句包含两部分
1、格式控制符,都是以%符号开始,用以描述格式规范
2、参数列表,比如变量名列表,与格式控制符相对应,是输出的对象、


printf修饰符及其意义
- #左对齐
width #域的步长
.prec #小数点右边的位数

printf格式符及其意义
%c #ASCII字符
%d #整型数
%e #浮点数,科学记数法
%f #浮点数
%o #八进制
%s #字符串
%x #十六进制数

在student中打印出字符串$2和整型数$8,并且$2之后tab,$8之后换行
#awk 'BEGIN {FS=","} {printf("%s\t%d\n",$2,$8)}' student

将数字65转换为ASCII码
#awk 'BEGIN {printf("%c\n",65)}'

将2014转换为浮点数,默认小数位六位
#awk 'BEGIN {printf("%f\n",2014)}'

打印出student文件中的第一个域和第三个域,并且第一个域的字符串和第三个域的字符串相差15个空格
#awk 'BEGIN {FS=","} {printf("%-15s\t%s\n",$1,$3)}' student

打印出student文件中的第一个域和第三个域,并且在行首加入第一个域的注释Name,第三个域的注释Phonenumber
#awk 'BEGIN {FS=",";print "Name\t\tPhonenumber"} {printf("%-16s%s\n",$1,$3)}' student

打印出浮点数控制在10为,小数点后保留三位的数
#awk 'BEGIN {printf("%10.3f\n",20141126)}' #如果数不满10位,则会按空格补齐
2011111.000 满10位
201.000 不满10位


===================================================================
内置字符串函数 awk提供了强大的内置字符串函数,用于实现文本的字符串替换、查找以及分隔等功能

awk字符串函数及其意义
gsub(r,s) #在输入文件中用s替换r
gsub(r,s,t) #在t中用s替换r
index(s,t) #返回s中字符串第一个t的位置
length(s) #返回s的长度
match(s,t) #测试s是否包含匹配t的字符串
split(r,s,t) #在t上将r分成序列s
sub(r,t,s) #将t中第1次出现的r替换为s
substr(r,s) #返回字符串r中从s开始的后缀部分
substr(r,s,t) #返回字符串r中从s开始长度为t的后缀部分

在passwd中把第一个域的root替换为"My name is root",并输出为:格式打印出来
#awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"my name is root",$1) {print $0}' /etc/passwd

在passwd中把所有域的root替换为"My name is root",并输出为:格式打印出来
#awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"My name is root") {print $0}' /etc/passwd

打印出abcdefg字符串中f出现的首位置
#awk 'BEGIN {print index("abcdefg","f")}'

打印出"This is a httpd server script"这串字符串的长度
#awk 'BEGIN {print length("This is a httpd server script")}'

测试"This is a httpd server script!!!"这串字符串中!的首位置
#awk 'BEGIN {print match("This is a httpd server sctipt!!!","!")}'

测试"This is a httpd server sctipt!!!"这串字符串中C的首位置(忽略大小写)
#awk 'BEGIN {IGNORECASE=1;print match("This is a httpd server sctipt!!!",/C/)}'

将字符串"This script is a httpd server script!!!"中第一个出现的sctipt替换为SCRIPT
#awk 'BEGIN {file="This script is a httpd server script!!!";sub(/script/,"SCRIPT",file);printf("%s\n",file)}'

将student文本中第一个域匹配Li行中的第一个出现的10替换为99
#awk 'BEGIN {FS=","} {$1~Li sub(/10/,"99",$0);print $0}' student

返回file文件中从第5个字符开始的后缀部分 file="This script is a httpd server script!!!"
#awk 'BEGIN {file="This script is a httpd server script!!!";print substr(file,6)}'

返回file文件中从第6个字符开始长度为9的后缀部分
#awk 'BEGIN {file="This script is a httpd server script!!!";print substr(file,6,9)}'

在student文件记录首部插入记录行号和域数,并且使用分隔符.进行分隔打印
#awk 'BEGIN {FS=","} {print NR,NF,$0}' OFS="." student




相关内容