awk命令作用:
文本处理
输出格式化的文本报表
执行算数运算
执行字符串操作
运行系统命令
等等
AWK的程序结构:
BEGIN 语句块
BEGIN语句块的语法
BEGIN {awk-commands}
BEGIN语句块在程序开始的使用执行,它只执行一次,在这里可以初始化变量。BEGIN是AWK的关键字,因此它必须为大写,注意,这个语句块是可选的。
BODY 语句块
BODY语句块的语法
/pattern/ {awk-commands}
BODY语句块中的命令会对输入的每一行执行,我们也可以通过提供模式来控制这种行为。注意,BODY语句块没有关键字。
END 语句块
END语句块的语法
END {awk-commands}
END语句块在程序的最后执行,END是AWK的关键字,因此必须为大写,它也是可选的。
让我们创建一个包含序号,学生姓名,科目名称和得分的文件 marks.txt。
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
4) Kedar English 85
5) Hari History 89
下面的例子中我们将会显示文件内容,并且添加每一列的标题
$ awk 'BEGIN{printf "Sr No\tName\tSub\tMarks\n"} {print}' marks.txt
上述代码执行后,输出以下内容
Sr No Name Sub Marks
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
4) Kedar English 85
5) Hari History 89
在程序的开始,AWK在BEGIN语句中打印出标题。然后再BODY语句中,它会读取文件的每一行然后执行AWK的print命令将每一行的内容打印到标准输出。这个过程会一直重复直到文件的结尾。
awk命令基本格式:
awk [options] file ...
awk调用方式:
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk
3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
命令实例:
#输出marks.txt的完整内容
$ awk '{print}' marks.txt
$ awk '{print $0}' marks.txt
#输出marks.txt每一行以空格为间隔的第一块内容,(默认以空格为间隔)
$ awk '{print $1}' marks.txt
#输出第二块内容
$ awk '{print $2}' marks.txt
$ awk '{print $3 "\t" $4}' marks.txt
#输出marks.txt文件中字符数大于18的行
$ awk 'length($0) > 18' marks.txt
$ awk 'length($0) > 18 {print $0}' marks.txt
#输出/etc/passwd文件中每行以:间隔的第一个域
$ cat /etc/passwd |awk -F ':' '{print $1}'
#输出access_stat4.log文件中含有content的行到gl.log文件中 >> 表示追加,> 表示覆盖
$ /bin/awk '/content/' access_stat4.log >> ./gl/gl.log
$ /bin/awk '/content/ {print $1}' access_stat4.log >> ./gl/gl.log
#输出test.log文件中含有content的行数
$ awk '/content/{++cnt} END {print "Count = ", cnt}' test.log
#输出test.log文件中含有content的行及其行数
$ awk '/content/{++cnt;print} END {print "Count = ", cnt}' test.log
#自定义间隔符,以+号为间隔符输出test.log文件每行的第一块
$ awk -F "+" '{print $1}' test.log
#以+或8为间隔符
$ awk -F "+|8" '{print $1}' test.log
#正则 输出test.log文件中不含有如下字符的行 正则表达式操作符使用 ~ 和 !~ 分别代表匹配和不匹配。
$ awk '{if($0 !~ /Googlebot|Baiduspider|Sogou|bingbot|Yahoo/) print $0}' test.log
#输出test.log文件中以空格为间隔第一块不含有如下字符的行
$ awk '{if($1 !~ /Googlebot|Baiduspider|Sogou|bingbot|Yahoo/) print $0}' test.log
#正则 输出test.log文件中含有 content/数字 的行
$ awk '{if($0 ~ /content\/[0-9]+/) print $0}' test.log
#排序 对nginx_access.log文件中第一块出现行数数量进行排序
$ awk '{print $1}' nginx_access.log |sort |uniq -c|sort -n #升序
$ awk '{print $1}' nginx_access.log |sort |uniq -c|sort -nr #降序
#统计某个文件夹下的所有文件占用的字节数
$ ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
#统计某个文件夹下的每个文件占用的字节数
$ ls -l |awk '{size=0;} {size=size+$5;} {print "[end]size is ", size}'
#条件语句
$ ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
#循环与数组
$ awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
awk内置变量:
awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
#此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。
#统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
$ 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:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh
#使用printf替代print,可以让代码更加简洁,易读
$ awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
while循环:
$ awk 'BEGIN{ test=100; total=0; while(i<=test) { total+=i; i++; } print total; }'
for循环:
$ awk 'BEGIN{ total=0; for(i=0;i<=100;i++) { total+=i; } print total; }'
$ awk 'BEGIN{ for(k in ENVIRON) { print k"="ENVIRON[k]; } }'
do 循环:
$ awk 'BEGIN{ total=0; i=0; do { total+=i; i++; }while(i<=100) print total; }'
awk脚本命令:
!/bin/awk -f
# all comment lines must start with a hash '#'
# name: student_tot.awk
# to call: student_tot.awk grade.txt
# prints total and average of club student points
# print a header first
BEGIN
{
print "Student Date Member No. Grade Age Points Max"
print "Name Joined Gained Point Available"
print"========================================================="
}
# let's add the scores of points gained
(tot+=$6);
# finished processing now let's print the total and average point
END
{
print "Club student total points :" tot
print "Average Club Student points :" tot/N
}
#输出nginx日志中每秒访问数超过40的时间点
/bin/awk -F '[][]' '{print $2}' /var/log/access.log |sort |uniq -c|sort -n | /bin/awk '$1 >= 40{print $0}'
#nginx日志访问ip量排序
awk '{print $1}' nginx_access.log |sort |uniq -c|sort -n
条件表达式
== != > >=
awk -F":" '$1=="mysql"{print $3}' /etc/passwd
awk -F":" '{if($1=="mysql") print $3}' /etc/passwd //与上面相同
awk -F":" '$1!="mysql"{print $3}' /etc/passwd //不等于
awk -F":" '$3>1000{print $3}' /etc/passwd //大于
awk -F":" '$3>=100{print $3}' /etc/passwd //大于等于
awk -F":" '$3<1{print $3}' /etc/passwd //小于
awk -F":" '$3<=1{print $3}' /etc/passwd //小于等于
#多分隔符
awk -F'[:#]' '{print NF}' helloworld.sh #指定多个分隔符: #,输出每行多少字段
awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6}' OFS='\t' helloworld.sh #制表符分隔输出多字段
awk -F'[:#/]' '{print NF}' helloworld.sh #指定三个分隔符,并输出每行字段数
awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9}' helloworld.sh #制表符分隔输出多字段
awk -F ‘[][]’ ‘{print $3;}’ data #以[和]为分隔符
每行都是数字的文件中,求平均值
gzcat default.log.gz | awk -F 'speed=|H/s&ssas' '{print $2}' | awk 'BEGIN{sum=0}{sum+=$1}END{print sum/FNR}'