awk:
文本处理三剑客:grep系,sed,awk grep系:grep,egrep,fgrep,基于PATTERN进行文本过滤; sed:流编辑器,逐行编辑器;模式空间,保持空间; awk:报告生成器;格式化文档输出; awk: Alfred Aho:贝尔实验室; Peter J Weinberger:贝尔实验室; Brian W Kernighan:贝尔实验室;K&R 《C语言程序设计 第二版》 CentOS/RHEL系:GNU awk,gawk; New awk,nawk; Old awk,oawk; gawk命令: gawk - pattern scanning and processing language 格式: gawk [ options ] 'program' file ... program:[/PATTERN/]{ACTION statement; ...} PATTERN部分:决定动作语句何时触发以及通过什么事件来触发; BEGIN, END ACTION statement:对数据进行特定的处理,通常放置在{}中; print, printf 基本概念: 分隔符: 输入分隔符: awk对数据进行处理时,会根据特定的标识符号对数据进行分段处理,这种标识符号就称为"输入分隔符",默认的输入分隔符是空白字符;如果指定的分隔符并没有被数据包括,则只有换行分隔符有效; 输出分隔符: awk对数据处理完成后,会以特定的标识符号对各个字段进行连接后输出,这种标识符号就称为"输出分隔符",默认的输出分隔符是空白字符; 记录:由换行符进行分隔的数据中一行,就称为一条记录(Record);通常在使用awk处理数据时,使用内置变量$0来保存整个记录的内容; 字段:经过分隔符分隔之后的每一个数据分段,都成为一个字段(Field);通常在使用awk处理数据时,使用$1,$2...$NF等内置变量来存储各个字段的数据; awk的工作原理: 1.首先,执行BEGIN{ACTION statement;...}语句块中的语句; 2.其次,从文件中或着标准输入读取一行,根据PATTERN的匹配结果执行后面的ACTION语句块中的内容;然后逐行重复该过程已完成数据处理,直到数据全部被读取完毕; 3.最后,在所有的语句块都执行完成之后,退出awk进程之前,执行END{ACTION statement;...}语句块中的语句; 注意: 1) BEGIN语句块在awk开始处理数据内容之前就被执行;通常用于生成表头;此语句块是可选语句块; 2) END语句块在处理完所有的数据之后,才会被执行;通常用于数据汇总;此语句块是可选语句块; 3) PATTERN语句块中的通用命令是最重要的部分,因此PATTERN语句块不能省略,但其中的ACTION可以省略,如果省略,则默认执行print动作,即:显示数据的各行; 4) awk在执行PATTERN语句块时,默认循环遍历数据中的各个记录; 常用选项: -f,--file program-file:从指定的文件中加载program语句块,而不是通过命令行给出相关的程序内容; -F,--field-separator fs:指定字段的输入分隔符;默认是空白字符; -v,--assign var=val:用于声明自定义变量并为变量赋值; awk的常用用法: 1.变量: 内建变量: FS:input field separator,输入字段分隔符,默认为空白字符; OFS:output field separator,输出字段分隔符,默认为空白字符; 示例: ~]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd RS:The input record separator,输入记录(行)分隔符,默认为换行符; 注意:即使指定了额外的输入记录分隔符,原有的换行符依然有效; ORS:The output record separator,输出记录分隔符,默认为换行符; 示例: ~]# awk -v RS=':' -v ORS='#' '{print $0}' /etc/passwd NF:The number of fields,每一行中的字段的总数; 示例: ~]# awk -F: '{print NF}' /etc/passwd 显示指定文件中每行中的字段的数量; ~]# awk -F: '{print $NF}' /etc/passwd 显示指定文件中每行中最后一个字段的内容; ~]# awk -F: '{print $(NF-1)}' /etc/passwd 显示指定文件中每行中倒数第二个字段的内容; NR:The total number of input records,行的总数;如果仅处理一个文件,可以将NR的值当作此文件中各行的行号; 示例: ~]# awk '{print NR}' /etc/fstab FNR:The input record number in the current input file,对于不同的文件分别统计其行的数量;即使处理多个文件,也可以显示每个文件中每行的行号; 示例: ~]# awk '{print FNR}' /etc/fstab /etc/issue FILENAME:The name of the current input file,当前正在被处理的文件的文件名; 示例: ~]# awk 'END{print FILENAME}' /etc/fstab ARGC:The number of command line arguments,命令行中参数的数量;包括awk命令本身,但不包括awk命令的选项部分和program部分; 示例: ~]# awk 'END{print ARGC}' /etc/fstab /etc/issue /etc/passwd ARGV:Array of command line arguments,由命令行中所有的参数构成的数组; 示例: ~]# awk 'END{print ARGV[1]}' /etc/fstab /etc/issue /etc/passwd 显示命令行中的第N个参数; 自定义变量: 定义方式: -v var_name=value 注意:变量名字母大小写敏感的; 示例: ~]# awk -v var='hello' -F: '{print $1"," var}' /etc/passwd 常用的ACTION: 2.print:Print the current record,以标准格式输出结果; 格式: print item1,item2,... 注意: 1) 各item之间需要使用","进行分隔; 2) 输出的各item可以是字符串,可以是数字,可以是当前记录中的字段,可以是变量,可以是awk的表达式; 3) 如果省略了item,则默认的item为$0,即:输出整行; 示例: ~]# awk '{print}' /etc/issue ~]# awk '{print $1,$3,$NF}' /etc/issue 3.printf:Format and print,以特定的格式输出结果; 格式: printf "FORMAT" item1,item2,... 注意: 1) 必须给出合适的输出格式; 2) 默认不会自动换行,如果想要在输出结果中换行显示,需要显式给出换行控制符号,即:\n; 3) FORMAT中需要为后面的每一个item单独指定一个格式化符号; 常用的FORMAT: %c:以ASCII码表中的内容显示字符信息; %d, %i:显示十进制整数; %e, %E:以科学计数法来显示数字;浮点类型; %f, %F:显示十进制数字的浮点形式; %g, %G:以科学计数法显示浮点数字; %u:显示无符号十进制数; %s:显示字符串; %x, %X:显示无符号的十六进制整数; %%:显示%; 修饰符: #[.#]:第一个数字用来控制显示宽度;第二个数字表示小数点的精度; 如:%5s, $8.3f -:表示采用左对齐方式显示;默认是右对齐; +:显示数字的正负符号; 示例: ~]# awk -F: '{printf "%20s:%-+5d\n",$1,$3}' /etc/passwd 4.操作符: 算术运算操作符: 双目运算符: x+y, x-y, x*y, x/y, x^y, x%y 单目运算符: -x:将正整数转换为负整数; +x:将字符串转换为数值; 示例: ~]# awk -F : 'END{print 100^2}' /etc/passwd 字符串操作符: 无任何操作符号时,即为字符串连接操作; 赋值操作符: =, +=, -=, *=, /=, ^=, %= ++, -- 比较操作符: ==, !=, >, >=, <, <= 示例: ~]# awk -F : '$3==1000{print $0}' /etc/passwd 模式匹配操作符: ~:操作符左侧的字符串是否能够被右侧的PATTERN所匹配; !~:操作符左侧的字符串是否不能被右侧的PATTERN所匹配; 示例: ~]# awk -F : '$NF~/bash/{print $0}' /etc/passwd 逻辑运算操作符: && || ! 示例: ~]# awk -F: '$3>=1000&&$3<=1100{print $0}' /etc/passwd 条件表达式: selector(condition)?if-true-expression:if-false-expression 示例: ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="SuperUser or Sysuser";printf "%20s: %-20s\n",$1,usertype}' /etc/passwd 5.PATTERN部分: 1) empty:空模式,不加区分地处理文件的每一行; 2) [!]/REGEXP/:仅处理[不]能被PATTERN匹配到的行; 示例: ~]# awk -F: '/^r/{print $0}' /etc/passwd ~]# awk -F: '!/n$/{print $0}' /etc/passwd 3) 关系表达式: $3>=1000 $NF~/bash/ 4) 行域,行范围: 关系表达式的逻辑运算:FNR>=10&&FNR<==20 示例: ~]# awk 'NR>=15&&NR<=20{print NR,$0}' /etc/passwd /REGEXP1/,/REGEXP2/: 从被REGEXP1匹配的行开始,直到被REGEXP2匹配的行结束,这期间的所有行;凡是属于此类的匹配结果,有多少组就显示多少组; 示例: ~]# awk -F: '/^r/,/^a/{print NR,$0}' /etc/passwd 5) BEGIN/END模式: BEGIN{} 仅在开始处理文件中的第一行文本数据之前执行一次的语句块;多用于输出特定格式的表头信息; 示例: ~]# awk -F: 'BEGIN{printf "%20s %10s %20s\n","USERNAME","USERID","SHELL"}NR>=15&&NR<=20{printf "%20s %10s %20s\n",$1,$3,$7}' /etc/passwd END{} 仅在文本处理完成但awk命令尚未退出时执行一次的语句块;多用于数据信息的汇总; 示例: ~]# awk -F: 'BEGIN{printf "%20s %10s %20s\n","USERNAME","USERID","SHELL"}NR>=15&&NR<=20{printf "%20s %10s %20s\n",$1,$3,$7}END{print "------------------------------------------------------------------\n",NR " users"}' /etc/passwd 注意: 1) BEGIN语句块,PATTERN语句块和END语句块的顺序,通常来讲是: BEGIN{}PATTERN{}END{} 2) BEGIN语句块和END语句块是可选的,但PATTERN语句块必须要给出; 6.常用的ACTIONS 1) 表达式(Expression) 2) 组合语句(Compound Statements) 3) 输入语句(Input Statements) 4) 输出语句(Output Statements) 5) 控制语句(Control Statements) 7.控制语句: if (condition) statement [ else statement ] while (condition) statement do statement while (condition) for (expr1; expr2; expr3) statement for (var in array) statement break continue exit [ expression ] switch (expression) { case value|regex : statement ... [ default: statement ] } next 1) if ... else: 语法: if (condition) statement [ else statement ] 使用场景:对awk取得的整行或某个字段做条件判断; 示例: ~]# awk -F: '{if($3>=1000){print "CommonUser:",$1}else{print "Sysuser:",$1}}' /etc/passwd ~]# awk '/^[^#]/{if(NF==6){print}}' /etc/fstab 分析磁盘上各个文件系统的空间利用率: ~]# df -h | awk -F% '/^\/dev/{print $1}' | awk '{if($NF>=80){print $1}}' 2) while循环: 语法: while (condition) statement 使用场景: a.对一行内的多个字段逐一做相同或类似的操作处理时使用; b.对数组中的各数组元素做遍历处理时使用; while循环的特点:条件为真,进入循环;一旦条件为假,则退出循环; 示例: ~]# awk '{i=1;while(i<=NF){print $i,length($i);i++}}' testfile 3) do ... while语句: 语法: do statement while (condition) 意义:与while循环相同,但statement语句段至少被执行一次; 4) for循环: 语法: for (expr1; expr2; expr3) statement expr1:variable assignment,变量赋初值; expr2:circle condition,循环条件判断; expr3:interation process,变量值修正方法; 示例: ~]# awk '{for(i=1;i<=NF;i++){print $i,length($i)}}' testfile for (var in array) statement 5) switch ... case语句 语法: switch (expression) { case value|regex:statement;case value2|regex2:statement;... [ default: statement ] } 使用场景: 用于进行字符串比较判断; 6) break和continue语句: break [n] continue 注意:其使用场景是行内多个字段间做循环时的循环控制方式; 示例: ~]# awk '{for(i=1;i<=NF;i++){if(length($i)<5){continue}else{print $i,length($i)}}}' testfile 7) next语句: 在awk处理数据时,提前结束对当前行的处理,而直接开始处理下一行; 示例: ~]# awk -F: '{if($3%2==1){next}else{print $1,$3}}' /etc/passwd ~]# awk -F: '{if($3%2==1)next;print $1,$3}' /etc/passwd 8.数组——Array 用户自定义的数组,一般使用关联数组:array_name[index_expression] 注意: 1) index_expression可以使用任意的字符串,但字符串必须放在双引号中; 2) 支持弱变量数组,即:如果某数组元素事先不存在,当引用该元素时,awk会自动创建此元素,并为此元素赋"空字符串"作为其初始值; 示例: ~]# awk 'BEGIN{name["leader"]="zhangsan";name["mem1"]="lisi";name["mem2"]="bob";print "Leader:",name["leader"],"Member:",name["mem1"],name["mem2"]}' ~]# awk 'BEGIN{name["leader"]="zhangsan";name["mem1"]="lisi";name["mem2"]="bob";for(i in name){print name[i]}}' 查看当前系统上所有服务的不同TCP状态的连接数量的统计: ~]# netstat -nalt | awk '/^tcp\>/{state[$NF]++}END{for(stat in state){printf "%15s: %-10d\n",stat,state[stat]}}' 用于统计本服务器web站点的每个用户的请求数值: ~]# awk '{ipaddr[$1]++}END{for(ip in ipaddr){print ip,ipaddr[ip]}}' /var/log/httpd/access_log 用于统计本服务器web站点的UV值: ~]# awk '{ipaddr[$1]++}END{for(ip in ipaddr){print ip,ipaddr[ip]}}' /var/log/httpd/access_log | wc -l 9.函数: 内建函数: 数值函数:Numeric Functions rand():返回一个介于0到1之间的随机数; sqrt():对于指定的数值进行开二次方; 字符串函数:String Functions length():计算给定字符串的长度; gsub(r, s [, t]):以r表示的模式来查找t表示的字符串中能够被匹配的内容,并将所有出现的内容替换成s表示的内容; split(s, a [, r [, seps] ]):以seps作为分隔符,利用r表示的模式进行匹配,将s代表的字符串分割之后,保存在a表示的数组中; 自定义函数: function name(parameter list) { statements }使用实例:
1.显示GID小于500的组;
awk -F: '$3<500{print $1}'/etc/group 2.显示默认的shell为nologin的用户; awk -F: '/nologin$/{print $1}' /etc/passwd awk -F: '$NF~/nologin/{print $1}' /etc/passwd awk -F: '$NF=="/sbin/nologin"{print $1}' /etc/passwd 3.显示eth0网卡文件的配置信息,注意,只显示等号后面的值; awk -F= '{print $2}' /etc/sysconfig/network-scripts/ifcfg-eth0 4.显示/etc/sysctl.conf文件中定义的内核参数:只显示名称; awk -F= '!/^#|^$/{print $1}' /etc/sysctl.conf 5.显示eth0网卡的ip地址,通过ifconfig命令结果进行过滤; ifconfig eth0 | awk '/inet addr/{print $2}' | awk -F: '{print $2}' 6.统计/etc/fstab文件中每个文件系统类型出现的次数; awk '!/^#|^$/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab 7.统计指定文件中每个单词出现的次数; awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){printf "%40s: %-5s\n",i,count[i]}}' /etc/grub2.cfg 8.统计httpd的访问日志(/var/log/httpd/access_log)中,每个客户端请求web资源的总次数; awk '{ipaddr[$1]++}END{for(ip in ipaddr){print ip,ipaddr[ip]}}' /var/log/httpd/access_log