您的位置:首页 > 其它

gawk入门及进阶

2017-05-23 20:18 225 查看
gawk入门及进阶

GNU awk

文本处理三工具:
grep 、egrep、fgrep :文本过滤工具,pattern
sed :行编辑器
模式空间 、保持空间
awk :报表生成器,格式化文本输出;

AWK :Aho,Weinberger,Kernighan,三位作者,在Unix上使用

New AWK :NAWK

gwak :GNU awk ,在Linux上使用

gawk : pattern scanning and processing language

基本用法 :gawk [option] 'program' FILE ...
program :PATTERN{ACTION STATEMENTS}
语句之间用分号分隔

选项:
-F :指明输入时用到的字段分隔符;
-v var=value :自定义变量;

1. print

print item1,item2,...

要点:
(1) 逗号作为分隔符,默认输出结果的分隔符是一个空白字符;
(2) 输出的各item可以是字符串,也可以是数值,当前记录的字段、变量或awk的表达式;
(3) 如省略item,相当于print $0,即输出全部;

2. 变量:【注意】引用变量不要加$符号
2.1 内建变量
FS  :input field seperator,默认为空白字符;
OFS :output field seperator,默认为空白字符;
如:]# awk -v FS=':' -v OFS=',' '{print $1,$2}' /etc/passwd
]# awk -v RS=':' '{print}' /etc/passwd

RS  :input record seperator,输入时的换行符;
ORS :output record seperator,输出时的换行符;
如:]# awk -v RS=':' -v ORS=' ' '{print}' /etc/passwd
root x 0 0 root /root /bin/bash
bin x 1 1 bin /bin /sbin/nologin

NF :number of field,字段数量
如:]# awk -v OFS='********' '{print NF,$NF,$0}'

【注意】引用变量不要加$符号:
此处{print NF}与{print $NF} 二者的输出效果不同,NF代表本行有多少个字段,$NF代表将NF的值作为变量名。
最终的执行效果为:输出本行的字段数量和本行最后一个字段。

NR :number record , 处理的行数,如果有多个文件则一起计数
FNR:file number recor ,多个文件分别计数
例1 :输出处理两个文件的行数,两个文件行数一起计算
]# awk '{print NR}' /etc/fstab /etc/issue
例2 :输出处理两个文件的行数,两个文件行数单独分别计算
]# awk '{print FNR}' /etc/fstab /etc/issue

FILENAME :  当前处理的文件的文件名
例1 :]# awk '{print FNR,FILENAME}' /etc/fstab /etc/issue

ARGC :命令行参数的个数;
ARGV :数组,保存的是命令行所给定的各参数;
如:
]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue
3
]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue
awk
]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue
/etc/fstab
]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue
/etc/issue

2.2 自定义变量 【注意】引用变量不要加$符号
(1) -v var=value

变量名区分字符大小写:
如:]# awk -v test="hello awk" 'BEGIN{print test}'
hello awk

(2) 在program中直接定义
如:]# awk 'BEGIN{test="hello awk";print test}'
hello awk

3. printf 命令

格式化输出 :printf FORMAT,item1,item2,...

(1) FORMAT必须给出;
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面的每个item指定一个格式化符号;

格式符:
%c  :显示字符的ASCII码
%d,%i:显示十进制整数
%e,%E :科学计数法数值显示
%f  :显示为浮点数
%g,%G : 以科学计数法或浮点形式显示数值
%s :显示字符串
%u :无符号整数
%% :显示%自身

如:]# awk -F: '{printf "Username: %s---UID:%d\n",$1,$3}' /etc/passwd
Username: root---UID:0
Username: bin---UID:1

修饰符:在格式符前面加修饰的符号,控制格式的显示机制
#[.#]:第一个数字控制显示的宽度(默认右对齐):第二个#标识小数点后的精度(可省略)
%3.1f
如:
]# awk  -F: '{printf "Username:%10s     UUID:%7.1f\n",$1,$3}' /etc/passwd
Username:       ntp     UUID:   38.0
Username:      abrt     UUID:  173.0

-   :代表左对齐
如:
]# awk  -F: '{printf "Username: %-10sUUID: %5.1f\n",$1,$3}' /etc/passwd
Username: ntp       UUID:  38.0
Username: abrt      UUID: 173.0

+   :显示数值的正负符号

4. 操作符

算术操作符:
x+y,x-y,x*y,x/y,x^y,x%y :
-x :单目操作符,变为负数
+x :转换为数值

字符串操作符:没有符号的操作符表示字符串连接

赋值操作符:
=,+=,-=,*=,/=,^=,%=
++,-- :自加,自减

比较操作符:
>,>=,<,<=,!=,==

模式匹配符:
~ :匹配
!~ :是否不匹配

逻辑操作符:
&&
||
!

函数调用:
function_name(arg1,arg2,...)

条件表达式:
selector?if-true-expression:if-false-expression
两个expression间用冒号:分隔

例如:]# awk -F':' '{$3>499?usertype="common user":usertype="sys user";printf "%-10s %5d %s\n",$1,$3,usertype}' /etc/passwd

5. pattern

(1) empty :空模式,匹配每一行
(2) /regular expression/ :仅对能被此处模式匹配到的行
如:]# awk '/nologin$/{print NR,$0}' /etc/passwd
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
【注意】此处不能print $1 。

(3) relational expression :关系表达式,结果为布尔型值,即真和假;结果为真才能被匹配处理;
真:结果为非0值,非空字符串
假:结果为0,空字符串
例1:
]# awk -F: '$3>499{printf "username:%-10s  UID:%3d\n",$1,$3}' /etc/passwd
username:achuDk      UID:500
username:gentoo      UID:501
例2:
]# awk -F: '$NF~/bash$/{printf "linenum:%-3d username:%-6s bash:%d\n",NR,$1,$NF}' /etc/passwd
linenum:1   username:root   bash:0
linenum:20  username:achuDk bash:0

(4) line ranges :行范围
startline,endline : /pat1/,/pat2/
【注意】不支持直接给出数字的格式
例如:
]# awk -F: '/^r/,/^h/{SUM=$3+$4;printf "Line record: %-2d  Uname: %10s  UID: %3d  GID: %3d  $3+$4: %3d\n",NR,$1,$3,$4,SUM}' /etc/passwd
Line record: 4   Uname:        adm  UID:   3  GID:   4  $3+$4:   7
Line record: 5   Uname:         lp  UID:   4  GID:   7  $3+$4:  11
例如:
]# awk -F: 'NR>=3&&NR<=10{print}' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin

(5) BEGIN/END 模式:
BEGIN{} :仅在开始处理文件中的文本之前执行一次,如:输出表头
END{}   :仅在文本处理完成之后,命令结束之前执行一次;

(6) 常用的action

1) Expression
2) Control statements : 控制语句:if,while等;
3) Compound statements : 组合语句;
4) input statements :输入语句
5) output statements :输出语句

(7) Control statements 控制语句

if(condition) {statements}
if(condition) {statements} else {statements}
while(condition) {statements}
do {statements} while(condition)
for(expr1;expr2;expr3) {statements}
break
continue
delete array[index]
delete array
exit
{ statements }

7.1 if-else

使用场景:对awk取得的整行或某个字段做条件判断;
语法:
单分支:'{if(condition) statement}'
多分支:'{if(condition) {statement} else {statement}}'

例1:找出/etc/passwd目录下UID<=100的用户打印Uname和UID:

18a1b
单分支语句示例:
]# awk -F: '{if($3<=10)print $1,$3}' /etc/passwd

多分支语句示例:
例1:]# awk -F: '{if($3<=499){printf "Super user: %s\n",$1}else{printf "Common user: %s\n",$1}}' /etc/passwd
例2:]# awk -F: '{if($NF=="/bin/bash") {print NR,$1}else {print $1,$NF}}' /etc/passwd

如:显示磁盘空间利用率大于2%的磁盘
]# df | awk '/^\/dev/{print $1,$6}' | awk -F% '{print $1}' | awk '{if($2>=2) printf "The used-percent of this partition has over %%2:%s \n",$1}'
The used-percent of this partition has over %2:/dev/sda2
The used-percent of this partition has over %2:/dev/sda1

7.2 while 循环
语法:while(conditiont) statement
条件为“真”,进入循环;条件为“假”,退出循环;

使用场景:对【一行内的多个字段】或对【数组中的各元素】逐一进行类似处理时使用,因为awk已经对整个文件的所有行进行循环;

示例:显示某文件中所有符合条件的行,对行内的每一个字段,显示字段本身和字段内字符的个数:
lenth(WORDS_NAME) :长度函数,显示某字段内字符的个数

结果:]# awk '/^[[:space:]]+kernel/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub.conf
kernel 6
/vmlinuz-2.6.32-642.el6.x86_64 30
ro 2
root=UUID=aadac335-a5b8-40ef-bdbe-ecb0fcc09d01 46
rd_NO_LUKS 10
rd_NO_LVM 9
LANG=en_US.UTF-8 16
rd_NO_MD 8
SYSFONT=latarcyrheb-sun16 25
crashkernel=auto 16
KEYBOARDTYPE=pc 15
KEYTABLE=us 11
rd_NO_DM 8

扩展条件:设定条件:仅显示length($i)>=6的字段
]# awk '/^[[:space:]]+kernel/{i=1;while(i<=NF) {if(length($i)>=6) {print $i,length($i)};i++}}' /etc/grub.conf
kernel 6
/vmlinuz-2.6.32-642.el6.x86_64 30

7.3 do-while循环
语法:do statemnet while(condition)
意义:至少执行一次循环体,即使condition为假

7.4 for循环
语法:for(expr1;expr2;expr3) statement
expr1 :控制变量初始化
expr2 :条件判断
expr3 :控制变量修正表达式
for-body :循环体
for(variable assignment;condition;iteration process) {for-body}

示例:显示某文件中所有符合条件的行,对行内的每一个字段,显示字段本身和字段内字符的个数:使用length()函数。

结果:]# awk '/^[[:space:]]+kernel/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub.conf

特殊用法:
能够遍历数组中的元素:
语法:for(var in array) {for-body}

7.5 switch语句 类似于bash中的case语句
语法:swtich(expression) {case VALUE1 or /REGEXP1/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}

7.6 break和continue 仅针对某一行内多个字段间的循环进行处理
break
:跳出第n层循环
continue  :提前结束本轮循环

7.7 next

提前结束对本行的处理,直接进入下一行的处理

示例:跳过UID号为奇数的行,仅显示UID号为偶数的用户

结果:]# awk -F: '{if($3%2!=0) {next} else {print $1,$3}}' /etc/passwd
root 0
daemon 2

8. array 数组

关联数组 :array[index-expression]

index-expression 类型
(1) 可使用任意字符串:
(2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;
【注意】
1、可使用任意字符串,字符串要使用双引号;
2、如果想判断数组中是否存在某元素或某元素是否为空时,要使用“index in array”格式进行,千万不要通过引用这个元素来判断

weekdays["mon"]="Monday"
例如:
]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"],weekdays["tue"]}'
Monday Tuesday

要遍历数组中的每个元素,要使用for循环;
for(var in array) {for-body}

例1:
]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
Monday
Tuesday

【注意】var会遍历array的每个索引;

例2:统计tcp协议的所有端口的连接状态:
]# netstat -tnl | awk '{print $4,$0}' | awk '/^[[:digit:]]+/{state[$NF]++}END{for(i in state) {print i,state[i]}}'
LISTEN 3

例3:统计所有进程中以root身份运行的进程
]# ps aux | awk '{user[$1]++}END{for(i in user);{print i,user[i]}}'
root 141

例4:统计/etc/fstab中所有fs出现的频率分布
]# cat /etc/fstab | awk '/^[[:alnum:]]/{fstype[$3]++}END{for(i in fstype) {printf "fs-type: %-10s  distribution: %d \n",i,fstype[i]}}'
fs-type: devpts      distribution: 1
fs-type: swap        distribution: 1
fs-type: sysfs       distribution: 1
fs-type: proc        distribution: 1
fs-type: tmpfs       distribution: 1
fs-type: ext4        distribution: 4


* 例5:统计文件中每个单词出现的次数:

]# awk -F: ‘{for(i=1;i<=NF;i++){words[$i]++}}END{for(i in words) {print i,words[i]}}’ /etc/passwd | sort -k 2 -nr

]# awk '{for(i=1;i<=NF;i++){fstype[$i]++}}END{for(i in fstype) {print i,fstype[i]}}' /etc/fstab

9. 函数

9.1 内置函数
rand() :返回0和1之间的随机数
如:]# awk 'BEGIN{print rand()}'
0.237788
【注意】只有第一次取是随机的,以后都会成为定值

字符串处理:
length([s]) :返回指定字符串的长度
sub(r,s,[t]) :以r表示的模式来查找t所表示的字符串中的匹配的内容,并将其第一次出现替 换为s所表示的内容;t可以省略
gsub(r,s,[t]) :全局替换

split(s,a[,r]) :以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;r可以省略
例如:统计netstat信息中的local address 去除端口号的数据:
]# netstat -tnl | awk '/^tcp/{split($4,ip,":");count[ip[1]]++}END{for(i in count) {print i,count[i]}}'
3
127.0.0.1 1
0.0.0.0 2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  awk gnu 编辑器