linux文本处理三剑客之awk

gawk - pattern scanning and processing language
awk是指向gawk命令的链接,它的工作模式是对文本逐行进行处理,将每一行按照输入时分隔符切片,每一个切片内容用awk内建的位置变量来存放,然后可以对每一片内容进行输出、循环等操作,不指定输入分隔符时默认分隔符为空白。

awk基本用法:awk [options] 'program' FILE...
  program: PATTERN{ACTION STATEMENTS},语句之间用分号分隔
示例:
[root@localhost scripts]# awk '/^UUID/{print $2,$4}' /etc/fstab
/boot defaults
swap defaults
选项options:
    -F:指明输入时用到的字段分隔符
    -v var=VALUE:自定义变量  
1.指明输入时字段分隔符为:,打印第1个切片内容,比如对/etc/passwd处理
[root@localhost scripts]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon

2.使用内建变量FS指明输入时的分隔符为冒号,打印第一个片段内容
[root@localhost scripts]# awk -v FS=':' '{print $1}' /etc/passwd
root
bin
1.print使用相关要点
    用法:print item1,item2,...
要点:
1.itm之间用逗号分隔
2.输出的各item可以是字符串,也可以是数值
3.如果省略item,默认print是:print $0,打印整行内容
1.print后面不跟item时,是将整行内容输出,也即是print $0
[root@localhost scripts]# awk -F: '{print}' /etc/passwd root:x:0:0:root:/root:/bin/bash
2.变量
2.1内建变量
    FS:input field seperator,输入时的分隔符,默认为空白字符
    OFS:output field seperator,输出时的分隔符,默认为空白字符
    RS:input record seperator,输入时的换行符
    ORS:output record seperator,输出时的换行符
    NF:number of field,字段数量
    NR:number of record,行数
    FNR:各文件分别计数:行数
    FILENAME:当前文件名
    ARGC:命令行参数的个数
    ARGV:数组,保存的是命令行所给定的各参数
内建变量相关示例
1.FS
[root@localhost scripts]# awk -v FS=':' '{print $1}' /etc/passwd
root
bin
2.OFS
[root@localhost scripts]# awk  -v FS=':' -v OFS='@@' '{print $2,$3,$7}' /etc/passwd
x@@0@@/bin/bash
x@@1@@/sbin/nologin
3.RS
[root@localhost scripts]# awk -v RS='o' '{print $1,$3}' /etc/passwd
4.ORS
[root@localhost scripts]# awk -v ORS='##' '{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash##bin:x:1:1:bin:/bin:/sbin/nologin##
5.NF
显示每行多少段
[root@localhost scripts]# awk -v FS=: '{print NF}' /etc/passwd
7
显示字后一段的值
[root@localhost scripts]# awk -v FS=: '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
6.NR
[root@localhost scripts]# awk '{print NR}' /etc/passwd
1
2
7.FNR
[root@localhost scripts]# awk '{print FNR}' /etc/fstab /etc/passwd
1
2
3
4
5
1
2
3
8.FILENAME
[root@localhost scripts]# awk '{print FILENAME}' /etc/fstab
/etc/fstab
9.ARGC
[root@localhost scripts]# awk '{print ARGC}' /etc/fstab
2
10.ARGV
[root@localhost scripts]# awk '{print ARGV[1]}' /etc/fstab
/etc/fstab
tips: ARGV[0]: awk ARGV[1]:/etc/fstab
2.2自定义变量
1. -v var=value
[root@localhost scripts]# awk -v test='hello awk' 'BEGIN{print test}'
hello awk
[root@localhost scripts]# awk -v test='hello awk' '{print test}' /etc/fstab   此时跟上文件名的作用是显示多少行 
hello awk
hello awk 
2. 在program中直接定义
[root@localhost scripts]# awk '{test="hello awk";print test}' /etc/fstab
hello awk
hello awk 
3.printf命令
格式化输出:printf FORMAT,item1,item2,...
格式符
    %c:显示字符的ASCII码
    %d,%i:显示十进制整数
    %e,%E:科学计数法数值显示
    %f:显示为浮点数
    %g,%G:以科学计数法或浮点形式显示数值
    %s:显示字符串
   %u:无符号整数
   %%:显示%自身
修饰符
 #[.#]:第一个数字控制显示的宽度,第二个#表示小数点后的精度,比如%3.1f
 默认是右对齐,-:左对齐
 +:显示数值的符号
相关示例
[root@localhost scripts]# awk -F: '{printf "ckh%s
",$7}' /etc/passwd
ckh/bin/bash
ckh/sbin/nologin
[root@localhost scripts]# awk -F: '{printf "Username:%-15s,UID:%d
",$1,$3}' /etc/passwd
Username:root           ,UID:0
Username:bin            ,UID:1
Username:daemon         ,UID:2
4.操作符
算术操作符
x+y,x-y,x*y,x/y,x^y,x%y
赋值操作符
=,+=,*=,/=,%=,^=
++,--
比较操作符:
>,>=,<,<=,!=,==
模式匹配符
~:是否匹配
!~:是否不匹配
逻辑操作符
&&
||
!
函数调用
    function_name(arg1,arg2,...)
条件表达式:
    selector?if-true-expression:if-false-expression
条件表达式示例
[root@localhost scripts]# awk -v FS=':' '{$3>=500?usertype="common user":usertype="Sysadmin or Sysuser";printf "%15s:%s ",$1,usertype}' /etc/passwd root:Sysadmin or Sysuser bin:Sysadmin or Sysuser
5.PATTERN
1. empty:空模式,匹配每一行
2. /regular expression/:仅处理能够被此处的模式匹配到的行
[root@localhost scripts]# awk '!/^UUID/{print $1}' /etc/fstab  //以UUID为开头的行之外的行
#
#
3. relational expression:关系表达式,结果有真有假;结果为真才会被处理
    真:结果为非0值,非空字符串
[root@localhost scripts]# awk -F: '$NF=="/bin/bash"{print $1,$7}' /etc/passwd  //最后一段是/bin/bash的字段
root /bin/bash
chengkaihua /bin/bash
[root@localhost scripts]# awk -F: '$NF~/bash$/{print $1,$7}' /etc/passwd  //以模式匹配bash结尾的片段
root /bin/bash
chengkaihua /bin/bash
4.line ranges:行范围
startline,endline:/pat1/,/pat2/
注意:不支持直接给出数字的格式
[root@localhost scripts]# awk -F: '(NR>=2&&NR<=5){print $1}' /etc/passwd
bin
daemon
5.BEGIN/END模式
BEGIN{}:仅在开始处理文本之前执行一次
END{}:仅在文本处理完成之后执行一次
[root@localhost scripts]# awk -F: 'BEGIN{print "    USERNAME        UID        
-------------------------------"}{printf "%15s,%10d", $1,$3}END{print "====================
            end"}' /etc/passwd
6.常用的action
1.EXPRESSIONS
2.Control statements:if,while等
3.Compound statements:组合语句
4.input statements
5.output statements
7.控制语句
if(condition){statements}
if(condition){statements}else{statements}
while(condition){statements}
do{statements}while(condition)
for(expr1;expr2;expr3){statements}
break
continue
delete aray[index]
delete array
exit
{ statements }
7.1 if-else
语法:if(condition)statement[else statement]
使用场景: 对awk取得的整行或某个字段做条件判断;
示例:
id号大于500为普通用户,其他为系统用户
[root@localhost scripts]# awk -F: '{if($3>=500){printf "Common User:%s ",$1}else{printf "Sysadmin or Sysuser:%s ",$1}}' /etc/passwd Sysadmin or Sysuser:root Sysadmin or Sysuser:bin
以/bin/bash结尾的字段
[root@localhost scripts]# awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
root
chengkaihua
每行字段大于5个,则显示整行
[root@localhost scripts]# awk  '{if(NF>5)print $0}' /etc/fstab
df命令中use大于百分之20的设备
# df -h | awk -F% '/^/dev/{print $1}' | awk '{if($NF>20)print $1}' 
7.2 while循环
语法:while(condition)statement
条件为"真",进入循环,条件为"假",退出循环
使用场景: 对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用

示例:

# awk '/^[[:space:]]*/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub2.cfg
# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)}; i++}}' /etc/grub2.cfg
7.3 do-while循环
语法:do statement while(condition)
    意义:至少执行一次循环体
7.4 for循环
语法:for(expr1;expr2;epr3) statement
for(variable assignment;iteration process) {for-body}
特殊用法:
能够遍历数组中的元素
语法:for(var in array){for-body}
# awk '/^[[:space:]]*linux16/{for(i=1;i<NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
7.5 switch语句
语法: switch(expression){case VALUE1 or  /REGEXP/;statement... default:statement}
7.6 break和continue
break [n]
continue
7.7 next
提前结束对本行的处理而直接进入下一行

示例:

显示偶数行
[root@localhost scripts]# awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
8.array
关联数组:array[index-expression]
index-expression:
  1.可使用任意字符串
  2.如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为"空串"
  若要判断数组中是否存在某元素,要使用"index in array"格式进行
给数组赋值:
weekdays[mon]="Monday"
给数组赋值并打印第一个值
[root@localhost scripts]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
若要遍历数组中的每个元素,要使用for循环
for(var in array){for-body}
[root@localhost scripts]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}'
Monday
Tuesday
统计netstat -atn命令结果中各状态结果的出现次数
[root@localhost scripts]# netstat -atn | awk '/^tcp>/{state[$NF]++}END{for(i in state){print i,state[i]}}'
ESTABLISHED 2
LISTEN 8
[root@localhost tmp]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /tmp/access.log
192.168.0.11 3
192.168.0.12 6
统计/etc/fstab文件中各文件系统类型出现的次数
[root@localhost ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab
swap 1
ext4 1
统计指定文件中每个单词出现的次数
[root@localhost ~]# awk '{for(i=1;i<NF;i++){word[$i]++}}END{for(i in word){print i,word[i]}}' /etc/fstab
mount(8) 1
Accessible 1
pages 1
reference, 1
9.函数
9.1 内置函数
rand():返回0和1之间一个随机数
[root@localhost ~]# awk 'BEGIN{print rand()}'
0.237788
字符串处理
length([s]):返回指定字符串的长度
sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容.也就是将t中的内容r替换为s
  # awk -F: '{print sub(o,O,$1)}' /etc/passwd
gsub(r,s,[t]):全局替换
split(s,a[],r):以r为分隔符切割字符串s,并将切割后的结果保存至a所表示的数组中
注意:awk中的数组从1开始编号
netstat -atn命令中客户端连接的ip出现次数,采用split分隔符
[root@localhost ~]# netstat -atn | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++;}END{for(i in count){print i,count[i]}}' 192.168.0.100 3 0.0.0.0 4
9.2 自定义函数
原文地址:https://www.cnblogs.com/ckh2014/p/14095686.html