三剑客包含:grep  sed  awk,此章节为awk,相对于grep的查找,sed的编辑,awk尤其擅长数据分析。

awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出,它支持用户自定义函数和动态正则表达式等先进功能。awk的处理文本和数据的方式是这样的:它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕)。

awk命令选项

-F

指定作为输入行的分隔符 默认为空格或tab键

-v

定义变量 var=value

’  ‘

引用代码块

-f

从脚本文件中读取awk命令

//

匹配代码块

{ }

命令代码块 多条命令分号分隔

BEGIN

初始化代码块 主要是引用全局变量 设置FS分隔符

END

结尾代码块

eg:  awk -F":" '{print $1,$3}'   test.txt

awk内置变量

FS

设置输入字段的分隔符 同-F

NF

浏览记录的字段个数

$NF

最后一个字段的值

NR

已读的记录数

FNR

与NR类似 不过多文件记录不递增,每个文件都从1开始

OFS

自定义分隔符 输出数据时每个字段以此分隔

ORS

自定义分隔符 输出数据时每行字段以此分隔,已空格分隔可将文件每一行合并为一行

\$n

当前记录的第n个字段,字段间由FS分隔

\$0

完整的输入记录

FIELDWIDTHS

字段宽度列表

举例

#awk  -F: 'BEGIN{FS=":";OFS="+++"}{print $1,$2,$3,$4}' /etc/passwd

root+++x+++0+++0

FS输入分隔符   OFS输出分隔符,数据拆分重组

#awk 'BEGIN{FIELDWIDTHS="2 3 4"}' {print $1,$2,$3} test

ab  cde   fast

FIELDWIDTHS以空格分隔的字段宽度 以指定的宽度替换分隔符

awk -F: '{print NF, $0}' /etc/passwd

7 root:x:0:0:root:/root:/bin/bash

显示字段个数 然后打印整行

允许多种运算和多种关系判断

常见的运算符

=    !=   ~[匹配]   &&[与]    ||    <  >   +  -  *    /

正则匹配元字符

^   $    .   *    ?    []    [^]    ()    |    \     x{m,n}  

实战举例

# awk '/^north/' datafile

以north开头

# awk '$3 ~ /^north/' datafile

第三列 匹配 north开头的

# awk '/^(no|so)/' datafile

no或者so 开头

# awk 'END {print "Number : "NF}' datafile

格式化文字  “字段数”:列数

# awk '/^[ns]/{print $1}' datafile

以n或s开头行的第一列

# awk '$5 ~ /\.[7-9]+/' datafile

第五列 匹配 . 1到多个7,8,9的行

# awk '$8 ~ /[0-9][0-9]$/{print $8}' datafile

匹配第八列,两个数字结尾,打印第八列

# awk -F: '{print "Number of fields: "NF}' /etc/passwd

以冒号作为字段分隔符,格式化文字,并打印列数

# awk -F"[ :]+" '{print NF}' /etc/passwd

以1到多个冒号或空格作为字段分隔符 ,并打印列数

# awk '$7 == 5' datafile

打印第七列是5 的行

# awk '$2 == "NW" || $1 ~ /south/ {print $1, $2}' datafile

第二列有NW,或者,第一列包含south的行,只打印第1,2列

# awk -F":" '/root/ {print $3 + 10}' /etc/passwd

匹配root字段,第三列+10并打印。

# awk '/southem/{print $8 % 2 }' datafile

取余数

# awk '$3 ~ /^Suan/ {print "Percentage: "$6 + .2 " Volume: " $8}' datafile

第三列正则匹配以Suan开头的,打印第6列加0.2 并且打印第八列

# awk '/^western/,/^eastern/' datafile

从以westem开头到以eastem开头的行

# awk '{print ($7 < 4 ? "high "$7 : "low "$7)}' datafile

//三目运算符 a?b:c 条件?成立结果1:不成立结果2

第三列小于4显示high$7

第三列大于4显示low$7

# awk '$3 == "Chris" {$3 = "Christian"; print $0}' datafile

赋值运算符,$3=christian


# awk '{$7%=3; print $7}' datafile

//$7 %= 3等价于$7 = $7 % 3

先将第七列取余,再赋值给第七列,打印第七列

流程控制

awk提供了完备的流程控制语句,这给工作中的的统计带来了极大的方便。

if条件

统计管理员和系统用户数量

awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd

while循环

循环打印10个数字

awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'

每行打印十次

awk -F: '{i=1; while(i<=10) {print $0; i++}}' passwd

for循环

循环打印5个数字

awk 'BEGIN{for(i=1;i<=5;i++){print i} }'

将每行打印10次

awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd

打印每列

awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd

数组

按索引遍历 将用户名定义为数组的值

awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd

按元素遍历(了解)

awk -F: '{username[x++]=$1} END{for(i=0;i<x;i++) print i,username[i]}' /etc/passwd

实战举例

awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd

统计/etc/passwd中各种类型shell的数量

Shells[i] 数组加索引,显示的就是值。

netstat -ant |grep :80 |awk '{access_stat[$NF]++} END{for(i in access_stat ){print i,access_stat[i]}}'

网站访问状态统计 

<当前时实状态 netstat> netstat -anpt

ss -an |grep :80 |awk -F":" '!/LISTEN/{ip_count[$(NF-1)]++} END{for(i in ip_count){print i,ip_count[i]}}' |sort -k2 -rn |head

统计当前访问的每个IP的连接数量

<当前时实状态 netstat,ss>

grep '07/Aug/2012' access_log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |awk '$2>100' |sort -k2 -rn

统计Apache/Nginx日志中某一天的PV量  <统计日志>

awk -F: 'length($1)==4{count++; print $1} END{print "count is: "count}' /etc/passwd

统计用户名为4个字的用户

调用内置函数length可以计算长度。

awk -v user=root -F: '$1 == user' /etc/paswd

-v定义变量

# var="bash"

# echo "unix script" |awk "gsub(/unix/,\"$var\")"

awk调用变量   -v定义变量

awk调用外部变量时,外部使用双引号,内部也使用双引号,但需要转义内部的双引号

格式化输出

printf函数

语法:

格式化几种格式
%s 字符类型 %d 数值类型
%f 浮点型,可以定义保留占15字符
- 表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,加\n

举例                                                                                                                                                                                                                         

# awk -F: '{printf "%-10s %-10s %-15s\n", $1,$2,$3}' /etc/passwd | head 
root x 0
bin x 1
daemon x 2

# awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd | head
|root | x | 0 |
|bin | x | 1 |
|daemon | x | 2 |

[root@localhost ~]# awk -F: '{printf "|%-15s| %-15s| %0.1f|\n", $1,$2,$3}' /etc/passwd | head
|root | x | 0.0|
|bin | x | 1.0|
|lp | x | 4.0|