016、awk命令
本文最后更新于 66 天前,其中的信息可能已经过时,如有错误请发送邮件到wuxianglongblog@163.com

awk命令

awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。
它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

一、awk基本介绍

基本格式:awk [options] 'program' file…
[root@blwsy ~]#awk –F:  '{print}'  /etc/passwd
  • program通常是被放在单引号或双括号中
  • patternactionpattern部分决定动作语句何时触发及触发事件 BEGIN,END ;
  • action statements对数据进行处理,放在{}内指明 print, printf
分割符、域和记录
  • awk执行时,由分隔符分隔的字段(域)标记$1,$2..$n称为域标识 。$0为所有域,注意:和shell中变量$符含义不同

  • 文件的每一行称为记录

  • 省略action,则默认执行 print $0 的操作

基本用法

awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file …

[root@blwsy ~]#awk –F:   '{print $1,$3,$7}’ /etc/passwd
  • option

-F 指明输入时用到的字段分隔符,不指定分割符是默认空格。

-v var=value: 自定义变量

awk -v FS=':' == awk -F:

  • action

print格式: print item1, item2, ...

逗号分隔符

各item形式不限,可以字符串,也可以数值,字段或者变量以及awk表达式

如省略item,相当于print $0 ;$0相当于打印文档自身

二、awk变量

内置变量

FS:输入字段分隔符

[root@blwsy ~]#awk -v FS=':' '{print $1,$3}' test.txt
apache              48
saslauth            498
postfix              89
gdm                 42
pulse                497
sshd                 74
tcpdump           72
francis              500
setroubleshoot  496
wsy                  501

OFS:输出字段分隔符

[root@blwsy ~]#awk -v FS=':' -v OFS=':' '{print $1,$3}' test.txt
apache:48
saslauth:498
postfix:89
gdm:42
pulse:497
sshd:74
tcpdump:72
francis:500
setroubleshoot:496
wsy:501

RS:输入的记录分隔符

[root@blwsy ~]#awk -v FS="." -v RS=" " '{print $1}' f1(一个文件)
a
bbb
dswwesdds
e3dew4cfv

ORS:输出的记录分隔符

[root@blwsy ~]#awk -v FS="." -v RS=" " -v ORS="#" '{print $1}' f1
a bbb dswwesdds#2133#dasfe#wd699#

NF:字段的数量

[root@blwsy ~]#awk '{print NF}' /etc/fstab
0
6
6
6
6

NR:记录号

[root@blwsy ~]#awk '{print NR,$0}' /etc/fstab 
1 
2 UUID=929873ac-4dca-40d2-9eeb-a755dbe56096 /boot     ext4   defaults    0  1
3 UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c   /  ext4    defaults  0  2
4 UUID=4acb218c-f541-44aa-a3e0-d491f336a609 /app       ext4  defaults 0   0
5 UUID=646ae8f4-0f05-4feb-aa7d-0fd8906fc8ce swap   swap    defaults   0   0

FNR:各文件分别计数,行号

[root@blwsy ~]#awk '{print FNR}' /etc/fstab /etc/inittab   两个文件分别记录行号
1
2
3
4
5
1
2
3
4
5
….
16

FILENAME:当前文件名

[root@blwsy ~]#awk '{print FILENAME}' /etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab

ARGC:命令行参数的个数

[root@blwsy ~]#awk '{print ARGC}'   /etc/fstab /etc/shadow  (参数个数为三,awk也算)

ARGV:数组,保存的是命令行所给定的各参数

[root@blwsy ~]#awk 'BEGIN {print ARGV[2]}'  /etc/fstab  /etc/inittab 
/etc/inittab

打印命令行的最后一个参数

[root@blwsy ~]#awk 'BEGIN {print ARGV[ARGC-1]}'  /etc/fstab /etc/inittab /etc/haha hi hello
hello
自定义变量

(1) -v var=value

(2) 在program中直接定义

[root@blwsy ~]#awk -v test="hello awk" '{print test}' /etc/fstab 
hello awk
hello awk
hello awk
hello awk
hello awk
[root@blwsy ~]#awk '{sex="male";print sex}' /etc/fstab
male
male
male
male
male
[root@blwsy ~]#awk '{sex="male";print sex,age;age=20}'
male 
male 20
male 20
male 20
male 20

三、格式化输出

printf命令(格式化输出)
格式化输出:printf  “FORMAT” , item1, item2, ...

(1) 必须指定FORMAT

(2) 不会自动换行,需要显式给出换行控制符,\n

(3) FORMAT中需要分别为后面每个item指定格式符

格式符:与item一一对应

%c: 显示字符的ASCII码

%d, %i: 显示十进制整数

[root@blwsy ~]#awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd

%e, %E:显示科学计数法数值

%f:显示为浮点数

[root@blwsy ~]#awk 'BEGIN{printf "%.2f\n",1.5*4}'

%g, %G:以科学计数法或浮点形式显示数值

%s:显示字符串

[root@blwsy ~]# awk -F: 'printf "%s",$1}’'etc/passwd 

%u:无符号整数

[root@blwsy ~]#awk 'BEGIN{printf "%u\n",1.5*4}'
6

%%: 显示%自身

[root@blwsy ~]#awk 'BEGIN{printf "%s%\n",1.5*4}'
6%
修饰符:

[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f

-: 左对齐(默认右对齐) %-15s

+:显示数值的正负符号 %+d

[root@blwsy ~]#df  |awk -v FS=% '$0 ~ "/dev/sd" {print $1}' |awk '$NF>=10 {printf "DevName:%-10s Used:%s%%\n",$1,$5}'
DevName:/dev/sda2  Used:68%
DevName:/dev/sda1  Used:38%

四、操作符

*模式匹配符:~:左边是否和右边匹配包含!~:是否不匹配
[root@blwsy ~]#awk '$0 ~ "^root" {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
*逻辑操作符:与&&,或||,非!
[root@blwsy ~]# awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd 
root
nfsnobody
*三目表达式
selector?if-true-expression:if-false-expression

[root@blwsy ~]#awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin ";printf "%15s:%s\n",$1,usertype}' /etc/passwd
*关系表达式

为非0时,即为真,才处理
为0或为空时,不处理

[root@blwsy ~]# awk -F:  'i=1;j=1{print i,j}' /etc/passwd (i=1时没有指定动作默认输$0,j=1时输出i ,j)
*行范围
[root@blwsy ~]#awk -F: ‘(NR>=10&&NR<=20){print NR,$1}' /etc/passwd
BEGIN/END模式
[root@blwsy ~]#awk -F: 'BEGIN{print " USER UID  \n--------------- "}{print $1,$3}END{print "=============="}' test.txt

  USER UID  
--------------- 

apache 48
saslauth 498
postfix 89
gdm 42
pulse 497
sshd 74
tcpdump 72
francis 500
setroubleshoot 496

wsy 501
==============

五、控制语句

if-else 对awk取得的整行或某个字段做条件判断

语法:if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2} else{statement3}

[root@blwsy ~]#echo {1..10} |awk '{n=1;while(n<=NF){if($n%2==0){print $n,"奇数"}else {print $n,"偶数"};n++}}'
1 偶数
2 奇数
3 偶数
4 奇数
5 偶数
6 奇数
7 偶数
8 奇数
9 偶数
10 奇数
while循环 对一行内的多个字段逐一类似处理时使用 对数组中的各元素逐一处理时使用

语法:while(condition){statement;…}

条件“真”,进入循环;条件“假”,退出循环

[root@blwsy ~]#cat /boot/grub/grub.conf  |awk '/^[[:space:]]*kernel/{i=1;while(i<=NF){print $i,length($i);i++}}'
kernel 6
/vmlinuz-2.6.32-696.el6.x86_64 30
ro 2
root=UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c 46
rhgb 4
crashkernel=auto 16
LANG=zh_CN.UTF-8 16
KEYTABLE=us 11
do-while循环

语法:do {statement;…}while(condition)

意义:无论真假,至少执行一次循环体

[root@blwsy ~]#awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);{print total}}'
5050
for循环

语法:for(expr1;expr2;expr3) {statement;…}

[root@blwsy ~]#cat /boot/grub/grub.conf  |awk '/^[[:space:]]*kernel/{for(i=1;i<=NF;i++){print $i,length($i)}}'
kernel 6
/vmlinuz-2.6.32-696.el6.x86_64 30
ro 2
root=UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c 46
rhgb 4
crashkernel=auto 16
LANG=zh_CN.UTF-8 16
KEYTABLE=us 11
continue 和break

continue 结束本次循环,继续执行下次循环

break 结束此次循环,后边可加数字表示跳出几层循环

计算1到100 所有偶数之和

[root@blwsy ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}'
2550
next

提前结束对本行处理而直接进入下一行处理(awk自身循环)

[root@blwsy ~]#awk -v FS=: '{if($3%2!=0) next;print $1,$3}' /etc/passwd

六、数组

关联数组:array[index-expression]

index-expression:

(1) 可使用任意字符串;字符串要使用双引号括起来

(2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历

计算etc/passwd中,shell脚本的类型及个数

[root@localhost ~]# awk -F: '{line[$7]++}END{for(i in line){print i,line[i]}}' /etc/passwd
/sbin/shutdown 1
/bin/bash 1
/sbin/nologin 29
/sbin/halt 1
/bin/sync 1

七、函数

数值处理:

rand():返回0和1之间一个随机数

[root@localhost ~]# awk 'BEGIN{srand();print int(rand()*100) }'     srand()函数要和rand()函数一起使用
84 
字符串处理:

length([s]):返回指定字符串的长度

[root@localhost ~]# awk 'BEGIN{print length("hello")}'
5

• sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s

[root@localhost ~]#echo "2008:08:08 08:08:08" | awk 'sub(/:/,“-",$1)' 
2008-08:08 08:08:08

• gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容

[root@localhost ~]#echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,“-",$0)' 
2008-08-08 08-08-08

• split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组 中,第一个索引值为1,第二个索引值为2,…

[root@localhost ~]# netstat -tan |awk '/^tcp\>/ && !($5 ~ "*"){split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
172.18.250.203 2
自定义函数

格式: function name ( parameter, parameter, ... ) { statements return expression }

自定义一个比较大小的awk函数

[root@localhost ~]#vim fun.awk
function max(a,b){
if (a>b)
  var=a
else
  var=b
return var
}
BEGIN{a=5;b=8;print max(a,b)}
[root@localhost ~]# awk -f fun.awk
8
awk中调用shell命令

用 system命令进行函数调用

空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了 awk的变量外其他一律用""引用起来。

[root@localhost ~]#awk BEGIN'{system("hostname") }'
localhost.localdomain
[root@localhost ~]#awk 'BEGIN{score=100; system("echo  your score is " score) }'
your score is 100

八、awk脚本

将awk程序写成脚本,直接调用或执行

[root@localhost ~]# cat fun.awk
#!/bin/awk -f
BEGIN{FS=":"}
{if($3>=1000)print $1,$3}
[root@localhost ~]#chmod +x fun.awk
[root@localhost ~]#./fun.awk  /etc/passwd
nfsnobody 65534

实例

1、统计/etc/fstab文件中每个文件系统类型出现的次数

[root@localhost ~]# cat /etc/fstab |awk '!($0 ~ "#"){print $0}'|awk '{line[$3]++}END{for(i in line){print i,line[i]}}'
  3
devpts 1
swap 1
sysfs 1
proc 1
tmpfs 1
ext4 3

2、统计/etc/fstab文件中每个单词出现的次数

[root@localhost ~]# awk '{for(i=1;i<=NF;i=i+1){print $i}}' /etc/fstab |sort|uniq -c|sort -nr|awk '{printf("%s %s\n",$2,$1)}'

3、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字

[root@localhost ~]# echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|awk 'gsub(/[^[:digit:]]/," ")'
     05   9    7        3

九、awk实践

1.3.1 函数的简单使用

[root@clsn6 ~]# awk '{gsub(/[0-9]+/,"");print}' /tmp/passwd 
root:x:::root:/root:/bin/bash
bin:x:::bin:/bin:/sbin/nologin
daemon:x:::daemon:/sbin:/sbin/nologin
adm:x:::adm:/var/adm:/sbin/nologin
lp:x:::lp:/var/spool/lpd:/sbin/nologin
sync:x:::sync:/sbin:/bin/sync

1.3.2 统计系统中的secure文件中谁在破解你的密码
1、找到谁在破解密码

[root@clsn6 awk]# awk '/Failed/{print $(NF-3)}' secure-20161219 |sort |uniq -c  |sort -nk1
      1 103.237.144.68
      1 122.228.238.66
      1 195.20.3.210
      1 85.93.5.71
··· 

2、过滤出包含Failed password的行 并统计每个ip地址出现的次数

[root@clsn6 awk]# awk '/Failed/{fa[$(NF-3)]++}END{for(pol in fa)print pol,fa[pol]}' secure-20161219 |sort -rnk2
218.65.30.25 68652
218.65.30.53 34326
218.87.109.154 21201
112.85.42.103 18065
112.85.42.99 17164
218.87.109.151 17163 

1.3.3 统计secure文件中每个用户,被同一ip破解多少次
1、进破解使用的用户及地址定向到文件中

[root@clsn6 awk]# awk '/Failed/{print $(NF-5),$(NF-3)}' secure-20161219 >user-ip.log 

2、对文件进行去重排序测

[root@clsn6 awk]# awk '{h[$1" "$2]++}END{for(p in h) print p,h[p]}' user-ip.log |head 
export 209.126.122.70 3
cvsadmin 209.126.122.70 3
user1 209.126.122.70 1
dasusr1 209.126.122.70 4
1 118.100.251.170 1
git 209.126.122.70 5
boss 195.154.50.61 1
user1 46.139.219.84 2
www 123.31.34.165 2
webmaster 195.154.50.61 1 

3、操作日志文件,取出数据

[root@clsn6 awk]# awk '/Failed/{h[$(NF-5)" "$(NF-3)]++}END{for(p in h) print p,h[p]}'  secure-20161219 |head
export 209.126.122.70 3
cvsadmin 209.126.122.70 3
user1 209.126.122.70 1
dasusr1 209.126.122.70 4
1 118.100.251.170 1 

1.3.4 统计nginx access.log文件中对ip地址去重并统计重复数

[root@clsn6 awk]# awk '{h[$1]++}END{for(i in h) print i,h[i]}' access.log |sort -nrk2 |head 
58.220.223.62 12049
112.64.171.98 10856
114.83.184.139 1982 

1.3.5 统计access.log文件中每个ip地址使用了多少流量
1、流量总计

[root@clsn6 awk]# awk '{sum=sum+$10}END{print sum}' access.log 
2478496663
[root@clsn6 awk]# awk '{sum=sum+$10}END{print sum/1024^3}' access.log 
2.30828 

2、每个ip使用的流量

[root@clsn6 awk]# awk '{h[$1]=h[$1]+$10}END{for(p in h) print p,h[p]/1024^2 }' access.log |sort -rnk2|column -t |head 
114.83.184.139   29.91
117.136.66.10    21.3922
116.216.30.47    20.4716
223.104.5.197    20.4705
116.216.0.60     18.2584 

1.3.6 统计access.log文件中每个ip地址使用了多少流量和每个ip地址的出现次数

[root@clsn6 awk]# awk '{count[$1]++;sum[$1]=sum[$1]+$10}END{for(pol in sum)print pol,count[pol],sum[pol]}' access.log |sort -nrk2 |column -t |head 
58.220.223.62    12049  12603075
112.64.171.98    10856  15255013
114.83.184.139   1982   31362956
117.136.66.10    1662   22431302
115.29.245.13    1318   1161468
223.104.5.197    961    21464856
116.216.0.60     957    19145329 

格式化命令

awk '{
  count[$1]++
  sum[$1]+=$10
}END{
  for(pol in sum)
  print pol,count[pol],sum[pol]
}' access.log |sort -nrk3 |head 

格式化后执行

[root@clsn6 awk]# awk '{
  count[$1]++
  sum[$1]+=$10
}END{
  for(pol in sum)
  print pol,count[pol],sum[pol]
}' access.log |column -t|  sort -nrk3 |head 
114.83.184.139   1982   31362956
117.136.66.10    1662   22431302
116.216.30.47    506    21466000
223.104.5.197    961    21464856
116.216.0.60     957    19145329
114.141.164.180  695    17219553
114.111.166.22   753    17121524
223.104.5.202    871    16911512
116.228.21.187   596    15969887
112.64.171.98    10856  15255013 

1.3.7 按要求得到最后面的格式的结果
文件内容

cat >next2.txg<< EOF
web01[192.168.2.100]
httpd            ok
tomcat            ok
sendmail          ok
web02[192.168.2.101]
httpd            ok
postfix           ok
web03[192.168.2.102]
mysqld           ok
httpd            ok
EOF 

想要的结果:

web01[192.168.2.100] httpd            ok
web01[192.168.2.100] tomcat           ok
web01[192.168.2.100] sendmail          ok
web02[192.168.2.101] httpd            ok
web02[192.168.2.101] postfix           ok
web03[192.168.2.102] mysqld           ok
web03[192.168.2.102] httpd            ok 

方法一:

[root@clsn6 awk]# awk '/^web/{tmp=$0} !/^web/{print tmp,$0}' next.txt 
web01[192.168.2.100] httpd            ok
web01[192.168.2.100] tomcat           ok
web01[192.168.2.100] sendmail         ok
web02[192.168.2.101] httpd            ok
web02[192.168.2.101] postfix          ok
web03[192.168.2.102] mysqld           ok
web03[192.168.2.102] httpd            ok 

方法二:

[root@clsn6 awk]# awk '/^web/{tmp=$0;next}{print tmp,$0}' next.txt 
web01[192.168.2.100] httpd            ok
web01[192.168.2.100] tomcat           ok
web01[192.168.2.100] sendmail         ok
web02[192.168.2.101] httpd            ok
web02[192.168.2.101] postfix          ok
web03[192.168.2.102] mysqld           ok
web03[192.168.2.102] httpd            ok 

next:停止处理当前行,从头开始处理下一行

[root@clsn6 awk]# seq 5 |awk 'NR==3{next}{print NR,$0}'
1 1
2 2
4 4
5 5
[root@clsn6 awk]# seq 5 |awk 'NR==1{next}{print NR,$0}'
2 2
3 3
4 4
5 5 

跳过偶数行

[root@clsn6 awk]# seq 5 |awk 'NR%2==0{next}{print NR,$0}'
1 1
3 3
5 5 

跳过奇数行

[root@clsn6 awk]# seq 5 |awk 'NR%2==1{next}{print NR,$0}'
2 2
4 4 

1.3.8 统计每个学生的总成绩和平均成绩
成绩文件

cat > chengji.txt <<EOF
cc 90 98 98 96 96 92
ll 70 77 85 83 70 89
ss 85 92 78 94 88 91
nn 89 90 85 94 90 95
bb 84 88 80 92 84 82
gg 64 80 60 60 61 62
EOF 

算出总和

[root@clsn6 awk]#  awk '{sum=0;for(i=2;i<=NF;i++)sum+=$i;print $1,sum}' chengji.txt 
cc 570
ll 474
ss 528
nn 543
bb 510
gg 387 

算出平均数

[root@clsn6 awk]#  awk '{sum=0;for(i=2;i<=NF;i++)sum+=$i;avg=sum/(NF-1);print $1,sum,avg}' chengji.txt 
cc 570 95
ll 474 79
ss 528 88
nn 543 90.5
bb 510 85
gg 387 64.5

格式化命令

awk '{
    sum=0
    for(i=2;i<=NF;i++)
    sum+=$i
    avg=sum/(NF-1)
    print $1,sum,avg
}' chengji.txt 

1.3.9 打印下面语句中字符数小于6的单词
文件内容

echo "I am clsn ops,I very like linux hahahaha." > text.txt 

shell方法

[root@clsn6 awk]# for i in `sed  's#,# #g' text.txt`

> do 
> [ ${#i} -lt 6 ] && echo $i
> done
> I
> am
> clsn
> ops
> I
> very
> like
> linux 

grep 方法

[root@clsn6 awk]# egrep -wo '[a-Z]{,6}' text.txt 
I
am
clsn
ops
I
very
like
linux 

awk方法

[root@clsn6 awk]# echo clsn |awk '{print length($1)}'
4
[root@clsn6 awk]# awk -F "[, ]" '{for(i=1;i<=NF;i++) if (length($i)<6) print $i}'   text.txt 
I
am
clsn
ops
I
very
like
linux 
谨此笔记,记录过往。凭君阅览,如能收益,莫大奢望。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇