awk基本用法
1. 简单实例 awk -F ":" '{print $3}' test.txt 分析: 把test.txt的做如下处理: 以:为分隔符,该行就被切割成多个”字段“(列) 各列为 $1 $2 .... 每一行,执行的操作为: '{print $3}' 这里的操作为: 打印这一行的第3列,打印后自动换行。 注意:1)如果不用-F指定分隔符,那么分隔符就是一个或多个空格 2)$1表示这一行的被分隔后的第1列 $2表示这一行的被分隔后的第2列 $0表示这一行! # awk '{print $0}' /etc/passwd 效果:把/etc/passwd的每1行打印输出。 # awk -F ":" '{print "--->" $0}' test.txt test.txt的内容如下: 2016-12-03-zhanshang 2016-11-30-lishi 2015-8-15-wangwu 打印 12月03日 11月30日 8月15日 awk -F "-" '{print $2 "月" $3 "日" }' test.txt /etc/passwd的内容格式如下: --------------------------------------- fab:x:400:1007::/tmp/fab:/sbin/nologin test1:x:912:912::/tmp/test1:/bin/bash aaa:x:913:913::/tmp/aaa:/bin/bash bbb:x:914:914::/tmp/bbb:/bin/bash ccc:x:300:1008::/tmp/ccc:/sbin/nologin --------------------------------------- 要求打印系统的所有用户的用户名以及家目录,类似如下效果, 要求使用awk实现 补充:对/etc/passwd进行分析 username=fab,home=/tmp/fab username=test1,home=/tmp/test1 username=aaa,home=/tmp/aaa username=bbb,home=/tmp/bbb username=ccc,home=/tmp/ccc awk -F ":" '{print "username=" $1 ",home=" $6 }' /etc/passwd 有销售表如下: sales.txt ------------------------------ zhangshan development 20000 lishi shichang 15000 wangwu yunwei 18000 ------------------------------ 把每个员工的工资打印输出: zhangshan的工资是20000 lishi的工资是15000 wangwu的工资是18000 打印当前目录下每个文件的大小 类似如下效果: a.txt:354bytes m:10234bytes ll | awk 'NR>1{print $9 ":" $5 "bytes" }' 补充: NR表示当前的行号(从1开始) 2. awk的BEGIN和END模块 ---------- sales.txt ---------------- zhangshan-2000 lishi-1000 wangwu-3000 ------------------------------------- # awk -F "-" 'BEGIN{sum=0} {sum=sum+$2} END{print sum}' sales.txt # 6000 BEGIN模块在分析第1行之前执行, END模块在分析最后1行之后执行 3.awk支持的运算符: 1) 算数运算 + - * / %(取余数) ++ a++ 就相当与 a=a+1 -- a-- 就相当与 a=a-1 2)赋值运算符 = += 例如: a+=b 就相当与 a=a+b -= *= /= %= 3) 关系运算符 > 大于 >= 大于或等于 < <= == 等于 != 不等于 4) 逻辑运算符 逻辑运算的结果,只有两种:真 假 逻辑与 && a >= 60 && a <= 100 特点: 1)只有两个都为真,结果才是真 2)只有第1个为真,后计算后一个 逻辑或 || a > 100 || a < 0 特点: 1)只有有1个是真,结果就为真! 2)如果前1个为真,那么后1个就不计算! ---------- sales.txt ---------------- zhangshan-2000 lishi-1000 wangwu-3000 ------------------------------------- 统计销售额超过1500的有多少人 awk -F "-" 'BEGIN{count=0} {$2>1500 && count++} END{print count}' sales.txt 打印当前目录下,文件大小超过100个字节的文件名 (了解) ll | awk '{if ($5 > 5000) {print $9}}' 4. 指定多种分隔符 使用awk来获取本机的IP地址 ifconfig eth0 | awk -F [" ":]+ 'NR==2{print $4}' 说明:[]表示其中的字符任取1个 +表示,其前导字符可连续任意多个。 [" ":]+ 就表示1个或多个的空格,和,1个或多个的:都作为分隔符 2012-12:zhangshan-3000:development 表示development部门的zhangshang在2012-12的工资为3000 要求打印工资(3000) echo 2012-12:zhangshan-3000:development | awk -F "[:-]" '{print $4}' 2012-12:zhangshan------3000:development echo 2012-12:zhangshan------3000:development | awk -F "[:-]+" '{print $4}' 打印eth0的广播地址 ifconfig eth0 | awk -F [" ":]+ 'NR==2{print $6}' 5. awk中的print和printf 1)print自动换行 printf不换行 2)printf能够指定输出格式 printf("name=%s,age=%d,height=%.2f", shell中也有printf命令 # printf "name=%s,age=%d,heig=%.2f \n" "pzj" 36 79.12345 name=pzj,age=36,heig=79.12 说明: %s, %d都称为占位符 %s 对应1个字符串 %d 对应1个整数 %f 对应1个带小数点的数 %.2f表示,小数点之后保留2位数字 \n表示换行符 实例: print #echo "2016-12-31 pzj 36" | awk '{print "name=" $2 "age=" $3}' name=pzjage=36 #echo "2016-12-31 pzj 36" | awk '{print "name=" $2 ", age=" $3}' name=pzj, age=36 printf pzj 36" | awk '{printf "name=%s,age=%d\n",$2,$3}' name=pzj,age=36 注意:shell编程中的printf和awk中使用的printf的区别: awk中的printf中需要使用逗号,来分隔各个参数 shell中的printf中需要使用空格,来分隔各个参数 6. awk中的正则匹配 打印当前目录中,以day开头的为文件的属主。 ll | awk '$9~/^day/{print $3 "," $9}' $9~/^day/ 表示,第9列如果以day开头,那么结果为真 ~可以理解为,是一个正则运算符。 注意: 正则表达式,其实,就是一个字符串的匹配规则。 使用形式: 字符串~正则表达式 $9~/^day/ 正则表达式,以/开头,以/结尾 ^day, 表示以day开头 打印当前目录下的所有普通文件的文件名 普通文件(ll的输出形式中,以-开头) wk '$1~/^-/{print $9}' 常用的正则表达式 /root/ 表示包含root /^root/ 表示需要以root开头 /root$/ 表示需要以root结尾 /br..t/ 表示,是5个字符的组合 前2个字符是br, 最后1个是t 中间的是任意2个字符。 即 . 用来匹配1个任意字符。 broot browt /br*t/ *用来匹配任意多个(包含0个)前导字符 比如: /br*t/ 可匹配 brt brrt brrrrrt /br+t/ +用来匹配1个或多个前导字符 /br+t/ 可匹配 brrt brrrrt /br?t/ ?用来匹配0个或1个前导字符 /br?t/ 可匹配 brt brrt /a[bcd]m/ []用来匹配方框号内的任意一个字符 /a[bcd]m/ 可匹配 abm acm adm a[^bcd]m []内的^,表示除了其后的任意1个字符。 a[^bcd]m 可匹配: a1m axm ... 不可匹配: abm acm adm 字符串 ~ 正则表达式 如果前面的字符串 匹配 后面的正则表达式,那么结果就为真 字符串 !~ 正则表达式 如果前面的字符串 不匹配 后面的正则表达式,那么结果就为真 /etc/passwd 1) 统计当前系统,有哪些用户可以登录系统 awk -F ":" '$9!~/nologin$/{print $1}' /etc/passwd awk -F ":" '$0!~/nologin$/{print $1}' /etc/passwd 2) 统计当前系统中,有多少个系统用户( 0 < uid < 500) 方式1 awk -F ":" 'BEGIN{count=0} {$3 > 0 && $3 < 500 && count++} END{print count}' /etc/passwd 方式2 awk -F ":" 'BEGIN{count=0} {if ($3 > 0 && $3 < 500) {count++}} END{print count}' /etc/passwd 3) 统计当前系统中,哪些用户的家目录在/home/下。 awk -F ":" '$6~/^\/home/{print $1 " " $6}' /etc/passwd awk的常用函数 1. gsub # awk 'BEGIN{info="this is a test2016test!"; \ gsub(/[0-9]+/,"XXX", info); \ print info}' 输出: this is a testXXXtest! gsub的作用:字符串的替换! [0-9] 就相当与 [0123456789],即0到9中的任意1个数字! [0-9]+ 就表示任意1个数字字符串,但是长度至少是1 小结: gsub(正则表达式, 替换字符串,源字符串) 1)把 字符串 "China-sz-20160812" 修改为 "China-sz-16" awk 'BEGIN{info="China-sz-20160812";gsub(/[0-9]+/, 16, info);print info}' 2) 有文件如下 ------------------------ zhangshan sz 3000 lishi sz 5000 ------------------------ 修改为 ------------------------ zhangshan 深圳 3000 lishi 深圳 5000 ------------------------ 方法1: awk '{$2=="sz" && $2="深圳"; print $0}' test.txt 方法2: awk '{gsub(/sz/, "深圳", $0); print $0}' test.txt 3) /etc/hosts的内容如下: ------------------------ 192.168.1.5 zhangshan.com 192.168.2.8 lishi.com ------------------------ 修改为 ------------------------ 10.0.1.5 zhangshan.com 10.0.2.8 lishi.com ------------------------ awk '{gsub(/192.168/, "10.0", $0); print $0}' test.txt 2. index awk 'BEGIN{info="this is a dog2016dog!"; print index(info, "dog")}' 注释:index(info, "dog") 在info中查找"dog", 返回"dog"第一次出现的位置 如果找不到,就返回0 如果返回值大于0,就表示包含指定的字符串。 补充:三目运算符 ?: awk中支持 三目运算符 双目运算符: a+b 单目运算符: a++ 三目运算符: print salary>20000 ? "买包" : "看包" awk 'BEGIN{salary=25000; print (salary>20000) ? "买包" : "看包"} 有文件如下 ------------------- zhangshan 深圳龙华区,长沙,上海 lishi 广州,北京 wangwu 武汉,深圳南山区 ------------------- 把需要到深圳出差的员工姓名打印输出。 要求使用多种方法实现,要求使用index 方法1: awk '$2~/深圳/{print $1}' test.txt 方法2: awk '{if (index($2, "深圳") > 0) {print $1}}' test.txt 注意awk中if语句的用法: if (条件) { 执行语句 } 3. match 匹配查找 有文件如下 ------------------- zhangshan 深圳龙华区,长沙,上海 13543827223 32010719801250 lishi 广州,北京 13223442888 43019519931233 wangwu 武汉,深圳南山区 13025879997 43019719911233 ------------------- 要求打印使用联通手机号码的员工 假设,联通号码是132和130开头的 awk '{if (match($3, /^13[20]/) > 0) {print $1}}' test.txt 打印所有90后的员工姓名 awk '{if (match($4, /[0-9][0-9][0-9][0-9][0-9][0-9]199[0-9]+/) > 0) {print $1}}' test.txt 正则表达式为:/[0-9][0-9][0-9][0-9][0-9][0-9]199[0-9]+/ 4. 字符串截取substr awk 'BEGIN{info="320109199105083480"; age=substr(info,7,4); print age}' 输出:1991 用法: substr(字符串,起始位置,长度) 打印年龄大于25岁的员工姓名 文件内容如下: ------------------------------------------------------------- zhangshan 深圳龙华区,长沙,上海 13543827223 32010719801250 lishi 广州,北京 13223442888 43019519931233 wangwu 武汉,深圳南山区 13025879997 43019719911233 --------------------------------------------------------------- awk '{ year=substr($4,7,4); \ age=2016-year; \ if(age > 25){print $1} \ }'\ test.txt if (条件){ 语句 } 如果 条件为真, 那么就执行后面大括号内的语句