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 (条件){ 语句 }
如果 条件为真, 那么就执行后面大括号内的语句