文本处理三剑客:grep系,sed,awk
grep系:grep,egrep,fgrep,基于PATTERN进行文本过滤;
sed:流编辑器,逐行编辑器;模式空间,保持空间;
awk:报告生成器;格式化文档输出;html
下面是三剑客其中之一的awk:linux
awk:其实就是gawk,是一种模式扫描和处理语言(Centos系/RHEL系中是通过GNU从新编写过的awk叫作gawk);
格式:gawk [ options ] 'program' file ...
program:[/PATTERN/]{ACTION statement;...} //只能有一对单引号,只能在program两侧
PATTERN部分:决定动做语句什么时候触发以及经过什么事件来触发;
BEGIN,END
注意:在有BEGIN语句块的前提下,后面的file有时候能够省略;
ACTION statement:对数据进行特定的处理,一般放置在{}中,并使用单引号进行引用;web
基本概念: 分隔符: 输入分隔符: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=value:用于声明自定义变量或数组并为变量赋值;//能够在BEGIN、PATTERN和END语句块中自定义变量,也能够声明数组;在选项当中每定义一个变量都须要再书写一次"-v" awk的经常使用用法: 1.变量: 内建变量: FS:输入字段分隔符,默认是空白字符; OFS:输出字段分隔符,默认的是空白字符; 示例: ~]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd //显示当前系统内存在用户的用户名、用户的uid、用户默认的shell(用“:”输入分隔,使用“:”输出分隔) root:0:/bin/bash bin:1:/sbin/nologin daemon:2:/sbin/nologin RS:输入记录(行)分隔符,默认为换行符; //换行符仍是生效的 ORS:输出记录分隔符,默认为换行符; //awk认为的换行符,真正输出换行的仍是原有的换行符 示例: ~]# awk -v RS=':' -v ORS='#' '{print $0}' /etc/passwd root#x#0#0#root#/root#/bin/bash bin#x#1#1#bin#/bin#/sbin/nologin NF:每一行当中字段的总数; 示例: ~]# awk -F: '{print NF}' /etc/passwd //显示指定文件中每行中的字段的数量 7 ... ~]# awk -F: '{print $NF}' /etc/passwd //显示指定文件中每行中最后一个字段的内容 /bin/bash /sbin/nologin ... ~]# awk -F: '{print $(NF-1)}' /etc/passwd //显示指定文件中每行中倒数第二个字段的内容 /root /bin ... NR:行的总数;若是仅处理一个文件,能够将NR的值当作文件中各行的行号; 示例: ~]# awk '{print NR}' /etc/fstab //显示一个文件的行数,处理单个文件时,能够记作行数 1 2 3 ... FNR:对于不一样的文件分别统计其行的数量;即便处理多个文件,也能够显示每一个文件中的行号; 示例: ~]# awk '{print FNR}' /etc/fstab /etc/issue //处理多个文件,显示每一个文件中的行号 FILENAME:当前正在被处理的文件的文件名; 示例: ~]# awk 'END{print FILENAME}' /etc/passwd /etc/fstab ARGC:命令行中参数的数量;包括awk命令自己但不包括awk选项部分也不包括program部分; 示例: ~]# awk 'END{print ARGC}' /etc/fstab /etc/issue /etc/passwd 4 AGRV:由命令行中全部的参数构成的数组;AGRV[0]:显示参数构成数组中的第一个参数awk; 示例:~]# awk 'END{print ARGV[1]}' /etc/fstab /etc/issue /etc/passwd //显示命令行中的第N个参数 /etc/fstab 自定义变量: 定义方式:-v var_name=value (变量字母严格区分大小写) 示例: ~]# awk -v var='hello' -F: '{print var","$1}' /etc/passwd //对当前系统内的用户打招呼:“hello,User” hello,root hello,bin awk经常使用的ACTION: 2.print:以标准格式输出文档; 格式: print item1,item2,... 示例: ~]# awk '{print}' /etc/issue CentOS release 6.7 (Final) Kernel \r on an \m ~]# awk '{print $1,$3,$NF}' /etc/issue CentOS 6.7 (Final) Kernel on \m 注意: 1)各个元素之间须要使用“,”进行分隔; 2)输出的各item能够是字符串,能够是数字,能够是当前记录中的字段,能够是变量,能够是awk的表达式; 3)若是省略了item,则默认的是item为$0,即:输出整行; 3.printf:以特定的格式输出结果; 格式: printf "FORMAT" item1,item2,... 示例: ~]# awk -F: '{printf "%20s:%-+5d\n",$1,$3}' /etc/passwd root:+0 bin:+1 daemon:+2 注意: 1)必须给出合适的输出格式; 2)默认不会自动换行,若是想要在输出结果中换行显示的话须要明确的给出换行控制符“\n”; 3)FORMAT中须要为后面的每个item单独指定一个格式化符号; 经常使用的FORMAT: %c:以ASCII码中的内容显示字符信息; %d,%i:显示十进制整数; %e,%E:以科学计数法来显示数字(浮点类型1.2,1.3,...);//类似:%g,%G:以科学计数法显示浮点数字 %f,%F:显示十进制数字的浮点形式; %u:无符号的十进制数; %o:无符号的八进制数; %s:显示字符串; %x,%X:显示无符号的十六进制数; %%:显示一个“%”符号; 修饰符: #[.#]:第一个数字用来控制显示宽度;第二个数字表示小数点后的精度; -:表示采用左对齐方式显示,默认是右对齐; +:显示数字的正负符号;(若是不是数字没有意义) 4.操做符: 算数运算操做符:(双目运算符优先级低于单目运算符) 双目运算符:x+y,x-y,x*y,x/y(y不能为0),x^y(优先级最高),x%y 单目运算符: -x:将正整数转换为负整数; +x:将字符串转换为数值; 示例:~]# awk -F : 'END{print 100^2}' /etc/passwd 字符串操做符: 无任何操做符号,即为字符串链接操做; 赋值操做符: =,+=,-=,*=,/=,^=,%= ++,--(步长为1) 比较操做符: ==,!=,>,<,>=,<= 示例: [root@chenliang ~]# awk -F: '$3==0{print $1}' /etc/passwd //取出系统中用户uid为0的用户 root 模式匹配操做符: ~:操做符左侧的字符串是否可以被右侧的模式PATTERN所匹配; !~:操做符左侧的字符串是否不可以被右侧的模式PATTERN所匹配; 示例: ~]# awk -F : '$NF~/bash/{print $0}' /etc/passwd //取出系统中shell为bash的用户 逻辑运算操做符:&& || ! 示例: ~]# awk -F: '$3>=100&&$3<=1100{print $0}' /etc/passwd //取出系统中用户uid大于等于100且小于等于1100的用户 usbmuxd rtkit 条件表达式: selector(condition)?if-true-expression:if-false-expression 示例: ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="SuperUser or Sysuser";printf "%20s: %-20s\n",usertype,$1}' /etc/passwd //系统中用户uid大于等于1000就标记为Common User,不然标记为SuperUser or Sysuser Super or Systemuser: root Super or Systemuser: bin 5.PATTERN(模式)部分: 1)empty:空模式,不加区分的处理文件的每一行; 2)[!]/REGEXP/:仅处理[不]能被PATTERN匹配到的每一行; 示例:~]# awk -F: '!(/^r/)&&/n$/{print $1}' /etc/passwd //取出系统中非r开头且不以n结尾的用户名 bin:x:1:1:bin:/bin:/sbin/nologin 3)关系表达式: 示例: ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="SuperUser or Sysuser";printf "%20s: %-20s\n",usertype,$1}' /etc/passwd //系统中用户uid大于等于1000就标记为Common User,不然标记为SuperUser or Sysuser Super or Systemuser: root Super or Systemuser: bin 4)行域,行范围: 关系表达式的逻辑运算:FNR>=10&&FNR<=20 示例: ~]# awk -F: 'FNR>=12&&FNR<=14{print $1}' /etc/passwd //取出/etc/passwd中12到14行的用户名 games gopher ftp /REGEXP1/,/REGEXP2/:从被REGEXP1匹配的行开始,直到被REGEXP2匹配的行结束,这期间的全部行;凡是属于此类的匹配结果,有多少组就显示多少组; 示例: ~]# awk -F: '/^n/,/^c/{print $1}' /etc/passwd //取出/etc/passwd中从n开头到c开头为用户名的用户名 nobody nfsnobody ntp cl1 5)BEGIN/END模式: BEGIN{}:仅在开始处理文件中第一行文本数据以前执行一次的语句块;多用于输出特定格式的表头信息; 示例: ~]# awk -F: 'BEGIN{printf "%20s %10s %20s\n","USERNAME","USEUID","SHELL"}NR>=15&&NR<=20{printf "%20s %10s %20s\n",$1,$3,$7}' /etc/passwd //在文件/etc/passwd中显示USERNAME ,USERUID ,SHELL为表头的15到20行的用户信息 USERNAME USERUID SHELL nobody 99 /sbin/nologin dbus 81 /sbin/nologin usbmuxd 113 /sbin/nologin vcsa 69 /sbin/nologin rpc 32 /sbin/nologin rtkit 499 /sbin/nologin 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.表达式 2.组合语句 3.输入语句 4.输出语句 5.控制语句 7)控制语句: (1)if ... else: 语法:if (condition) statement [ else statement ] 使用场景:对awk取得的整行或某个字段作条件判断; 示例: ~]# awk -F: '{if($3>=1000){print $1}else{print "Username: ",$1}}' /etc/passwd //uid大于等于1000的用户,若是不符合条件的用户就在用户名签名标识“Username: ”字样 Username: root Username: bin ~]# awk '/^[^#]/{if(NF==6){print}}' /etc/fstab //输出/etc/fstab文件中非#号开头的以空白字符分隔的含有6个字段的行 /dev/mapper/vg_chenliang-lv_root / ext4 defaults 1 1 UUID=ceeb9f75-73ea-412f-a33a-1704433e538b /boot ext4 defaults 1 2 /dev/mapper/vg_chenliang-lv_swap swap swap defaults 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 分析磁盘上各个文件系统的空间利用率: ~]# df -h | awk -F% '/^\/dev/{print $1}' | awk '{if($NF>=80){print $1}}' 9 (2)while循环: 语法:while (condition) statement 使用场景: a.对一行内的多个字段逐一作相同或相似的操做处理时使用; b.对数组中的各数组元素作遍历处理时使用; while循环的特定:条件为真,进入循环;一旦条件为假,则退出循环; 示例: ~]# vim testfile Hello! My Linux World! Let's go ~ ~]# awk '{i=1;while(i<=NF){print $i,length($i);i++}}' testfile //判断testfile中以空白字符分隔的每一个字段的字符数 Hello! 6 My 2 Linux 5 World! 6 Let's 5 go 2 ~ 1 (3)do ... while语句: 语法:do statement while (condition) //意义:与while循环相同,但statement语句段至少被执行一次; 示例: ~]# awk '{do{print $i,length($i);i++}while(i<=NF)}' testfile //判断testfile中以空白字符分隔的每一个字段的字符数 Hello! My Linux World! Let's go ~ 33 Hello! 6 My 2 Linux 5 World! 6 Let's 5 go 2 ~ 1 (4)for循环: 语法: for (expr1; expr2; expr3) statement //第一种语法 expr1:变量赋初始值; expr2:循环条件判断; expr3:变量值的迭代处理(变量值修正方法); 示例: ~]# awk '{for(i=1;i<=NF;i++){print $i,length($i)}}' testfile //判断testfile中以空白字符分隔的每一个字段的字符数 Hello! 6 My 2 Linux 5 World! 6 Let's 5 go 2 ~ 1 for (var in array) statement //第二种语法 示例: awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(i in BASH){printf "%15s:%i\n",i,BASH[i]}}' /etc/passwd /sbin/shutdown:1 /bin/bash:2 /sbin/nologin:29 /sbin/halt:1 /bin/sync:1 (5)switch ... case语句: 语法:switch (expression) { case value1|regex1:statement;case value2|regex2:statement; ... [ default: statement ]} 使用场景:用于字符串比较判断; (6)break语句和continue语句: break [n] 示例: [root@chenliang ~]# awk '{for(i=1;i<=NF;i++){if(length($i)<5){break}{print $i,length($i)}}}' testfile Hello! 6 continue 注意:其使用场景是行内多个字段间作循环时的循环控制方式; 示例: ~]# awk '{for(i=1;i<=NF;i++){if(length($i)<5){continue}else{print $i,length($i)}}}' testfile Hello! 6 Linux 5 World! 6 Let's 5 (7)next语句: 在awk处理数据时,提早结束对当前行的处理,而直接开始处理下一行; 示例: ~]# awk -F: '{if($3%2==1){next}else{print $1,$3}}' /etc/passwd root 0 ~]# awk -F: '{if($3%2==1)next;print $1,$3}' /etc/passwd root 0 (8)数组——Array 用户自定义的数组,通常使用关联数字:array_name[index_expression] 注意: 1)index_expression可使用任意的字符串,但字符串必需要放在双引号中; 2)支持弱变量数组,即:若是某数组元素事先不存在,当引用该元素时,awk会自动建立此元素,并为此元素赋“空字符串”做为其初始值; 示例: 1.[root@chenliang ~]# awk 'BEGIN{name["leader"]="zhangsan";name["mem1"]="lisi";name["mem2"]="wangwu";print "Leader: ",name["leader"],"\nMember: ",name["mem1"],name["mem2"]}' Leader: zhangsan Member: lisi wangwu 2.[root@chenliang ~]# awk 'BEGIN{name["leader"]="zhangsan";name["mem1"]="lisi";name["mem2"]="wangwu";for(i in name){print name[i]}}' wangwu zhangsan lisi 3.查看当前系统上全部服务的不一样TCP状态的链接数量的统计; ~]# netstat -nalt | awk '/^tcp\>/{state[$NF]++}END{for(stat in state){printf "%15s: %-10d\n",stat,state[stat]}}' ESTABLISHED: 1 LISTEN: 10 4.用于统计本服务器web站点的每一个用户的请求数值: ~]# awk '{ipaddr[$1]++}END{for(ip in ipaddr){print ip,ipaddr[ip]}}' /var/log/httpd/access_log 172.16.0.1 3 172.16.74.1 3 5.用于统计本服务器web站点的UV值(访问量): ~]# awk '{ipaddr[$1]++}END{for(ip in ipaddr){print ip,ipaddr[ip]}}' /var/log/httpd/access_log | wc -l (9)函数: 内建函数: 数值函数: rand():返回一个介于0-1之间的随机数; 示例: [root@chenliang ~]# awk 'BEGIN{print rand() }' 0.237788 sqrt():对于指定的数值进行开二次方; 示例: [root@chenliang ~]# awk 'BEGIN{print sqrt(5) }' 2.23607 字符串函数: length():计算给定字符串的长度; 示例: [root@chenliang ~]# awk 'BEGIN{print length(123456789) }' 9 gsub(r, s [, t]):以r表示的模式来查找t表示的字符串中可以被匹配的内容,并将全部出现的内容替换成s表示的内容; 示例: ~]# awk 'BEGIN{filed="This is a test text !";gsub(/text/,"file",filed);print filed}' This is a test file ! split(s, a [, r [, seps] ]):以seps做为分隔符,利用r表示的模式进行匹配,将s表明的字符串分割以后,保存在a表示的数组之中; 示例: 示例1~]# awk 'BEGIN{demo="learning linux is very happy ~";split(demo,DEMO," ");for(i in DEMO){print i,DEMO[i]}}' 4 very 5 happy 6 ~ 1 learning 2 linux 3 is 示例2~]# awk 'BEGIN{print split("123#456#678", myarray, "#")}' 3 自定义函数: 在命令行中自定义函数:function name(parameter list) { statements } 在脚本中自定义函数: function 函数名(参数表){ 函数体 } function f(p, q, a, b) # a and b are local { ... } 示例: 写两个函数计算最小和最大数,从main函数中调用这些函数(自定义函数示例转自http://www.yiibai.com/awk/awk_user_definede_functions.html): # Returns minimum number function find_min(num1, num2) { if (num1 < num2) return num1 return num2 } # Returns maximum number function find_max(num1, num2) { if (num1 > num2) return num1 return num2 } # Main function function main(num1, num2) { # Find minimum number result = find_min(10, 20) print "Minimum =", result # Find maximum number result = find_max(10, 20) print "Maximum =", result } # Script execution starts here BEGIN { main(10, 20) } 在执行上面的代码后,会获得以下结果: Minimum = 10 Maximum = 20