linux文本处理工具三剑客:grep、sed和awk。其中grep是一种文本过滤工具,sed是文本行编辑器,而awk是一种报表生成器,就是对文件进行格式化处理的,治理的格式化不是文件系统的格式化,而是对文件内容进行各种排版,进而格式化显示。
awk运行方式有三种:
(1)awk命令行
#awk
(2)awk 程序文件:将所有的awk命令插入一个单独文件,然后调用
#awk –f 文件路径
(3)awk脚本
awk 基本格式:awk [options] 'program' file…
• program:编程语言
• pattern和action:
• pattern部分决定动作语句何时触发及触发事件 BEGIN,END
BEGIN:在文件格式化操作开始之前事先执行的一次操作;通常用于输出表头或者作出一个预处理操作
END:在文件格式化操作开始之后,命令退出之前执行的一次操作;通常用于输出表尾或者作出清理操作
• action statements:动作语句,可以是多个语句组成,各语句之间使用分号分割;如{print,printf}
options:
-F[] 输入字段分隔符;
-v 变量名 =值:变量赋值
-f 路径
awk在处理文本时也是 一次读取一行文本,然后根据输入分隔符(默认空格)进行切片,切成n个片段,然后将每一片都赋予awk内部的一个变量当中来保存,这些变量名为$1,$2等到最后一个,awk可以对这些片段单独进行处理,显示某一段,并进行处理,如计数、运算等
1.awk的输出命令之一:print
print格式: print item1, item2, ...
要点:
(1) 逗号分隔符;输出分隔符默认为空白字符
(2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式
(3) 如省略item,相当于print $0
2.awk的输出命令之二:printf格式化输出
格式化输出:printf “FORMAT”, item1, item2, ...
(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面每个item指定格式符
• 格式符:与item一一对应
%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身
[root@centos6 ~]#awk -F: '{printf "username:%-15s uid:%-5d\n",$1,$3}' /etc/passwd
username:root uid:0
username:bin uid:1
username:Root uid:0
username:daemon uid:2
username:adm uid:3
username:GAMES uid:0
• 修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,
%3.1f :
[root@centos6 ~]#awk -F: 'BEGIN{printf "%.2d %1.2f\n",1.73333,3.1111}' 01 3.11
左对齐(默认右对齐)
%-15s
经典例子:查看分区利用率大于10%的分区,并打印(先把%去掉)
[root@centos6 ~]#df |awk -v FS="%" '$0 ~ "/dev/sd" {print $1}'|awk '$NF>=10 {printf "devicename:%-15s used:%s%%\n",$1,$5}' devicename:/dev/sda2 used:85% devicename:/dev/sda3 used:63% devicename:/dev/sda1 used:20%
printf和print区别:
awk中同时提供了print和printf两种打印输出的函数。
其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
3.变量
变量:内置和自定义变量
3.1、内置变量
FS:输入字段分隔符,默认为空白字符 (等同于-F:)
[root@centos6 ~]#awk -v FS=':' '{print $1,$3}' /etc/passwd root 0 bin 1 Root daemon 2 adm 3 GAMES lp 4 [root@centos6 ~]#awk -F: '{print $1,$3}' /etc/passwd root 0 bin 1 Root daemon 2 adm 3 GAMES lp 4
OFS:输出字段分隔符,默认为空白字符
[root@centos6 ~]#awk -v FS=':' -v OFS='#' '{print $1,$3}' /etc/passwd root#0 bin#1 Root# daemon#2 adm#3
RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效
[root@centos6 ~]#cat f aaa fferrb fggrefd.fgrgf bbbbb mmsmsmfm fgbfk.f fvc.werr ewregtrb.ew wereg [root@centos6 ~]#awk -v FS='.' -v RS=" " '{print $1}' f aaa fferrb fggrefd mmsmsmfm fgbfk ewregtrb wereg
ORS:输出记录分隔符,输出时用指定符号代替换行符
[root@centos6 ~]#awk -v FS='.' -v RS=" " -v ORS="#" '{print $1}' f
aaa#fferrb#fggrefd#mmsmsmfm##fgbfk#ewregtrb##wereg #
NF:字段数量 awk -F: ‘{print NF}’ /etc/fstab,引用内置变量不用$
[root@centos6 ~]#awk -F" " '{print NF}' /etc/fstab 0 1 2 10 1 9 12 1
NR:行号
[root@centos6 ~]#awk '{print NR,$0}' /etc/fstab 1 2 # 3 # /etc/fstab 4 # Created by anaconda on Tue Jul 10 20:16:55 2018 5 # 6 # Accessible filesystems, by reference, are maintained under '/dev/disk' 7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info 8 # 9 UUID=69175cc3-0636-46ac-9190-84a4bfa546ed / ext4 defaults
FNR:各文件分别计数,行号
[root@centos6 ~]#awk '{print FNR}' /etc/fstab /etc/inittab 1 2 3 4 5 6 1 2 3 4 5
FILENAME:当前文件名
awk '{print FILENAME}’ /etc/fstab
ARGC:命令行参数的个数
[root@centos6 ~]#awk '{print ARGC}' /etc/fstab /etc/shadow 3 3 3 3 3
注意:awk 也是一个参数
ARGV:数组,保存的是命令行所给定的各参数
[root@centos6 ~]#awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab awk
打印命令行的最后一个参数
[root@centos6 ~]#awk 'BEGIN {print ARGV[ARGC-1]}' /etc/fstab /etc/inittab /etc/haha hi hello hello
3.2、自定义变量
自定义变量(区分字符大小写)
(1) -v var=value
[root@centos6 ~]#awk -v a="i miss you" 'BEGIN{print a}' i miss you
(2) 在program中直接定义
[root@centos6 ~]#awk 'BEGIN{a="hi";print a}' hi [root@centos6 ~]#awk '{sex="male";print sex,age;age=20}' /etc/fstab male
/age=20在变量后边定义时,第一次age没值则为假不输出,后面会输出 male 20 male 20 male 20 male 20
对变量进行多次赋值时,注意b="$a",不能用单引号,它会完全转义。
[root@centos6 ~]#a="i love you";awk -v b="$a" '{c=b;print c}' /etc/fstab i love you i love you i love you i love you
注意:在内部定义变量=字符串时,字符串必须加引号,不然会被当成变量报错,但是变量=数字时,不用加引号
4.操作符
比较常用的几个:
算术表达式
[root@centos6 ~]#awk 'BEGIN{print 2^5}' 32 [root@centos6 ~]#awk 'BEGIN{print 15%4}' 3 [root@centos6 ~]#awk 'BEGIN{n=2;print n+=2 }' 4
模式匹配操作符:
~:左边是否和右边匹配包含
!~:是否不匹配
[root@centos6 ~]#awk '$0 ~ "^root"{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash [root@centos6 ~]#awk -F: '$3 == 0{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash
条件表达式(三目表达式):
selector?if-true-expression:if-false-expression
[root@centos6 ~]#awk -F: '{$3>=1000?usertype="com user":usertype="sys user";printf "username:%-15s usertype:%s\n",$1,usertype}' /etc/passwd username:root usertype:sys user username:bin usertype:sys user username:Root usertype:sys user username:daemon usertype:sys user username:adm usertype:sys user
关系表达式 为非0时,即为真,才处理 为0或为空时,不处理 !0=1 !Num=0 (Num为任意非0的值)
[root@centos6 ~]#awk 'BEGIN{print i++;print i}' 0 1 [root@centos6 ~]#awk 'BEGIN{print ++i;print i}' 1 1
行范围(不能用行号)
[root@centos6 ~]#cat /boot/grub/grub.conf |awk '/default/,/hidden/' default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu [root@centos6 ~]#cat /boot/grub/grub.conf |awk 'NR>=2&&NR<=7' # # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg.
打印奇数行
[root@centos6 ~]#seq 10|awk 'i=!i'
1 3 5 7 9
打印偶数行
[root@centos6 ~]#seq 10|awk '!(i=!i)' 2 4 6 8 10
5.常用动作:
(1)变量赋值
(2)控制语句
if-else
此语句使用场景:对awk取得的整行或某个字段做条件判断
计算男生平均成绩,女生平均成绩,总平均成绩,
要求输出结果
姓名 分数 性别
mage 100 male
lilin 90 female
yunzhen 85 female
xiaoxiao 55 male
男生平均成绩:xx
女生平均成绩: xx
总平均成绩: xx
[root@centos6 ~]#awk 'BEGIN{printf "%-13s%-5s%-6s\n","姓名","分数","性别"} {printf "%-15s%-6s%-6s\n",$1,$2,$3;if($NF=="male"){count++;sum+=$2}else{count1++;sum1+=$2}sum3+=$2} END {printf "男生平均成绩:%.2f\n",sum/count;printf "女生平均成绩:%.2f\n",sum1/count1;printf "总平均成绩:%.2f\n",sum3/NR}' score.txt 姓名 分数 性别 mage 100 male l ilin 90 female yunzhen 85 female xiaoxiao 55 male 男生平均成绩:77.50 女生平均成绩:87.50 总平均成绩:82.50
while循环
语法:while(condition){statement;...}
条件“真”,进入循环;条件“假”,退出循环
此语句使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用
[root@centos6 ~]#awk 'BEGIN{i=1;while(i<=1000000){sum+=i;i++};print sum}' 500000500000
for循环
特殊用法:能够遍历数组中的元素
[root@centos6 ~]#awk 'BEGIN{for(i=1;i<=1000000;i++){sum+=i};print sum}' 500000500000
break和continue
next: 提前结束对本行处理而直接进入下一行处理(awk自身循环)
计算1-100偶数之和
[root@centos6 bin]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}' 2550
计算1-100奇数之和
root@centos6 bin]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i};print sum}' 2500
仅显示uid为偶数的用户名和其uid
[root@centos6 bin]#awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd root 0 daemon 2 lp 4 shutdown 6
6.awk数组
关联数组:array[index-expression]
index-expression:
(1)可以使用任意字符串;字符串要使用双引号括起来
(2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
若要遍历数组中的每个元素,要使用for循环
• for(var in array) {for-body}
• 注意:var会遍历array的每个索引
[root@centos6 bin]#awk -F: '{line[$7]++}END{for (i in line) {print i,line[i]}}' /etc/passwd /sbin/shutdown 1 /bin/bash 4 /sbin/nologin 28 /sbin/halt 1 /bin/sync 1
7.awk函数
数值处理:
rand():返回0和1之间一个随机数,要想随机生成任意一个数,则前面要加上srand()
[root@centos6 ~]#awk 'BEGIN{srand();print int(rand()*100)}' 85
字符串处理:
length([s]):返回指定字符串的长度(字符串里面有空格则包含)
[root@centos6 ~]#awk 'BEGIN{print length("i miss you")}' 10
sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s
举例:
[root@centos6 ~]#echo "2018:08:30 08:59:05"|awk 'sub(/:/,"-",$1)' 2018-08:30 08:59:05
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
举例:
提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字
[root@centos6 ~]#echo 'Yd$C@M05MB%9&Bdh7dq+YVixp3vp'|awk 'gsub(/[^[:digit:]]/," ",$0)'
注意:这里只能用 单引号引住字符串
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2....
举例:
[root@centos6 ~]#netstat -tan|awk '/^tcp\>/&&!($5 ~ "*"){split ($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}' 172.18.250.74 1
8.awk中调用shell命令
system命令
• 空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了 awk的变量外其他一律用""引用起来。
[root@centos6 ~]#awk 'BEGIN{score=100;system("name=ms;echo $name score is "score )}' ms score is 100
9.awk脚本
将awk程序写成脚本,直接调用或执行
向awk脚本传递参数
• 格式: awkfile var=value var2=value2... Inputfile
• 注意:在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通 过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变 量都需要一个-v参数
[root@centos6 ~]#cat a.awk #!/bin/awk -f {if($3>=min&&$3<=max)print $1,$3} [root@centos6 ~]#chmod +x a.awk [root@centos6 ~]#./a.awk -F: min=100 max=200 /etc/passwd usbmuxd 113 avahi-autoipd 170 abrt 173