awk进阶
我们所学的centos7,awk,也就是gawk
[root@node02 tmp]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 Jun 4 19:05 /usr/bin/awk -> gawk
awk能够对原始数据进行格式化展示,适合处理各种数据格式化任务。
使用变量
awk该编程语言一特性就是使用变量存取值,支持两种类型变量
- 内置变量
- 自定义变量
awk的一些内置变量,存放处理数据文件中的数据字段和记录的信息。
内置变量
字段和记录分隔符
已知awk使用$1 $2 $3
的形式记录字段的位置,以此类推,awk默认分隔符是空格
。
以及可以使用-F
选项修改分隔符,NR
内置变量指定行号。
[root@node02 tmp]# awk -F ":" 'NR==1,NR==5{print $1}' /etc/passwd
root
bin
daemon
adm
lp
awk数据字段和记录变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcwX1rQY-1678373545845)(http://book.luffycity.com/linux-book/shell%E5%BC%80%E5%8F%91/pic/image-20201012094708670.png)]
案例
awk逐行处理文本的时候,以输入分割符为准,把文本切成多个片段,默认符号是空格
当我们处理特殊文件,没有空格的时候,可以自由指定分隔符特点
FS变量就是控制分隔符的作用
[root@node02 tmp]# cat num.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
[root@node02 tmp]# awk 'BEGIN{FS=","}{print $1,$2,$3}' num.txt
data11 data12 data13
data21 data22 data23
data31 data32 data33
还可以通过修改OFS变量,控制输出时的分隔符。
[root@node02 tmp]# gawk 'BEGIN{FS=",";OFS="|"}{print $1,$2,$3}' num.txt
data11|data12|data13
data21|data22|data23
data31|data32|data33
[root@node02 tmp]# gawk 'BEGIN{FS=",";OFS=" | "}{print $1,$2,$3}' num.txt
data11 | data12 | data13
data21 | data22 | data23
data31 | data32 | data33
数据变量
除了字段和记录分隔符变量,awk还提供了些内置变量用于了解数据的变化。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gl7QZqHd-1678373545847)(http://book.luffycity.com/linux-book/shell%E5%BC%80%E5%8F%91/pic/image-20201012101257625.png)]
ARGC和ARGV变量允许awk从shell中获取命令行参数的总数,但是awk不会把脚本文件当作参数的一部分
ARGC变量表示命令行上的参数,包括awk命令和文件名
[root@node02 tmp]# awk 'BEGIN{print ARGC}'
1
[root@node02 tmp]#
[root@node02 tmp]# awk 'BEGIN{print ARGC}' data.txt
2
ARGV数组值从索引0开始,表示awk本身,索引1表示第一个命令行参数
[root@node02 tmp]# awk 'BEGIN{print ARGV[0]}' data.txt
awk
[root@node02 tmp]# awk 'BEGIN{print ARGV[0],ARGV[1]}' data.txt
awk data.txt
[root@node02 tmp]# awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2]}' data.txt
awk data.txt
[root@node02 tmp]# awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2]}' data.txt xxxx
awk data.txt xxxx
awk内置变量的引用不用加美元符。
ENVIRON变量
该变量用关联数组提取shell环境变量,注意点:关联数组用文本字符串
作为数组的索引值,而不是数值。
在计算机科学中,关联数组(英语:Associative Array),又称映射(Map)、字典(Dictionary)是一个抽象的数据结构,它包含着类似于(键,值)的有序对。一个关联数组中的有序对可以重复(如C++中的multimap)也可以不重复(如C++中的map)。
数组索引中的key是shell的环境变量名,值是shell环境变量的值。
[root@node02 tmp]# awk 'BEGIN{print ENVIRON["HOME"],ENVIRON["PATH"]}'
/root /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
awk跟踪数据字段和记录时,变量FNR,NF和NR
用起来就很方便了,比如你不知道awk到底分隔了多少个数据字段,可以根据NF变量获取最后一个数据字段。
FNR FNR:各文件分别计数的行号
NF NF:number of Field,当前行的字段的个数(即当前行被分割成了几列),字段数量
NR NR:行号,当前处理的文本行的行号。
案例
[root@chaogelinux ~]# awk 'BEGIN{FS=":";OFS=" - "}{print $1,$NF}' /etc/passwd | head -3
root - /bin/bash
bin - /sbin/nologin
daemon - /sbin/nologin
NF变量就记录了字段的数量,因此$NF
也就是打印最后一个字段。
NR和FNR变量
FNR
和NR
变量类似,FNR变量含有当前数据文件中已经被处理过的记录数量NR变量含有已处理过的记录总数。
看下案例差别
[root@chaogelinux ~]# awk 'BEGIN{FS=":"}{print $1,"FNR="FNR}' /etc/passwd | head -5
root FNR=1
bin FNR=2
daemon FNR=3
adm FNR=4
lp FNR=5
可以看出,FNR
变量是记录处理的记录数量,也就是行数。
那NR和FNR的区别在哪?
[root@chaogelinux ~]# cat /tmp/pwd.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@chaogelinux ~]# awk 'BEGIN{FS=":"}{print $1,"FNR="FNR,"NR="NR}END{print "There ware",NR,"records processed"}' /tmp/pwd.txt /tmp/pwd.txt
root FNR=1 NR=1
bin FNR=2 NR=2
daemon FNR=3 NR=3
adm FNR=4 NR=4
lp FNR=5 NR=5
root FNR=1 NR=6
bin FNR=2 NR=7
daemon FNR=3 NR=8
adm FNR=4 NR=9
lp FNR=5 NR=10
There ware 10 records processed
我们会发现,FNR变量的值在awk处理第二个文件数据的时候被重置,而NR变量则在处理第二个数据文件时继续统计。
也就是我们利用AWK处理多个文件的时候,NR和NFR的区别就出来了
Josen的小结
awk里,内置变量无需加$
awk 'BEGIN{print ENVIRON["HOME"],ENVIRON["PATH"]}'
自定义变量
shell脚本与awk变量
awk允许自定义变量在程序中使用,awk自定义的变量可以是任意数目的字母,数字,下划线,不得已数字开头,而且区分大小写。
例如
[root@chaogelinux ~]# awk 'BEGIN{testing="Hello chaoge.";print testing}'
Hello chaoge.
[root@chaogelinux ~]# awk 'BEGIN{v1="超哥nb";print v1;v1="超哥不错哦";print v1}'
超哥nb
超哥不错哦
数值计算
[root@chaogelinux ~]# awk 'BEGIN{x=4;x=x*2+3;print x}'
11
命令行与变量赋值,花式用法
使用awk命令可以给脚本中的变量赋值
该作用可以不改变脚本的情况下,改变脚本的作用。
[root@chaogelinux ~]# cat data
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
[root@chaogelinux ~]#
[root@chaogelinux ~]#
[root@chaogelinux ~]#
[root@chaogelinux ~]#
[root@chaogelinux ~]# awk -f script1 n=2 data
data12
data22
data32
[root@chaogelinux ~]#
[root@chaogelinux ~]# cat script1
BEGIN{FS=","}
{print $n}
[root@chaogelinux ~]# awk -f script1 n=3 data
data13
data23
data33
使用命令行参数定义变量会有一个问题,设置了变量之后,这个值在代码的BEGIN部分不可用。例如
[root@chaogelinux ~]# cat script2
BEGIN{print "The starting value is",n;FS=","}
{print $n}
[root@chaogelinux ~]#
[root@chaogelinux ~]#
[root@chaogelinux ~]# awk -f script2 n=3 data
The starting value is
data13
data23
data33
发现这里只是打印了第三列的值,但是明没有在BEGIN里输出n的值
这里可以用-v选项解决,允许在awk的BEGIN开始之前设定变量。
[root@chaogelinux ~]# awk -v n=3 -f script2 data
The starting value is 3
data13
data23
data33
处理数组
为了能够在单个变量中,存储多个值,许多编程语言都提供了数组,awk也支持关联数组
功能,也就是可以理解为是字典
的作用。
例如
"name":"chaoge"
"age":18
关联数组的索引可以是任意文本字符串,每一个字符串都可以对应一个数值。
定义数组变量
语法
var[index]=element
var是变量名字,index是索引,element是值
案例
[root@chaogelinux ~]# awk 'BEGIN{student["name"]="超哥";print student["name"]}'
超哥
关联数组计算
[root@chaogelinux ~]# awk 'BEGIN{num[1]=6;num[2]=7;sum=num[1]+num[2];print sum}'
13
遍历数组变量
关联数组的问题是必须要知道索引是什么,否则无法取值。
可以利用for循环遍历出所有的索引。
for (var in array)
{
语句
}
例如
[root@chaogelinux ~]# awk 'BEGIN{
> var["a"]=1
> var["b"]=2
> var["d"]=3
> var["h"]=4
> for (s in var)
> {print "Index: ",s," - Value:",var[s]}}'
Index: h - Value: 4
Index: a - Value: 1
Index: b - Value: 2
Index: d - Value: 3
注意,索引值的返回是没有顺序的,但是对应的值是唯一的。
删除数组变量
语法
delete array[index]
一旦删除了索引,就无法用用它提取元素了。
[root@chaogelinux ~]# awk 'BEGIN{
var["a"]=1
var["b"]=2
var["d"]=3
var["h"]=4
for (s in var)
{print "Index: ",s," - Value:",var[s]};delete var["d"];print "----";for (s in var){print "Index:",s,"Value:",var[s]}}'
使用模式
awk的模式,我们已知有BEGIN和END俩关键字来处理,数据流开始与结束两个模式。
正则表达式
正则表达式必须出现在要控制的脚本左花括号前面。
# 匹配含有data的记录
[root@chaogelinux ~]# awk 'BEGIN{FS=","}/data/{print $1}' data
data11
data21
data31
匹配操作符
(matching operator)匹配操作符是波浪线~
,来看下如何用
匹配操作符(~) 用于对记录或字段的表达式进行匹配
$1 ~ /^data/
$1表示记录中的第一个数据字段,该正则会过滤出第一个字段以文本data开头的所有记录。
例如
[root@chaogelinux sed_awk]# tail -10 /etc/passwd
pyyu01:x:1005:1005::/home/pyyu01:/bin/bash
pyyu02:x:1006:1006::/home/pyyu02:/bin/bash
pyyu03:x:1007:1007::/home/pyyu03:/bin/bash
pyyu04:x:1008:1008::/home/pyyu04:/bin/bash
pyyu05:x:1009:1009::/home/pyyu05:/bin/bash
pyyu06:x:1010:1010::/home/pyyu06:/bin/bash
pyyu07:x:1011:1011::/home/pyyu07:/bin/bash
pyyu08:x:1012:1012::/home/pyyu08:/bin/bash
pyyu09:x:1013:1013::/home/pyyu09:/bin/bash
pyyu10:x:1014:1014::/home/pyyu10:/bin/bash
# 匹配出有关pyyu的行
# $1 表示针对第一列处理
# ~ 按照后面的表达式进行匹配
# $NF 最后一个字段的值,NF获取有几列数据
[root@chaogelinux sed_awk]# awk -F ":" '$1 ~ /^pyyu/{print $1,$2,$3,$NF}' /etc/passwd
pyyu01 x 1005 /bin/bash
pyyu02 x 1006 /bin/bash
pyyu03 x 1007 /bin/bash
pyyu04 x 1008 /bin/bash
pyyu05 x 1009 /bin/bash
pyyu06 x 1010 /bin/bash
pyyu07 x 1011 /bin/bash
pyyu08 x 1012 /bin/bash
pyyu09 x 1013 /bin/bash
pyyu10 x 1014 /bin/bash
排除语法
搜索出除了以a,b,c开头的行
[root@chaogelinux ~]# head -5 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@chaogelinux ~]# head -5 /etc/passwd | awk -F : '$1 !~ /^[a-c]/{print $1,$NF}'
root /bin/bash
daemon /sbin/nologin
lp /sbin/nologin
Josen的小结
awk 'BEGIN{v1="Josen不错";print v1;v2="Shea也不错";print v2}'
[root@localhost ~]# awk 'BEGIN{x=4;x=x*2+3;print x}'
11
[root@localhost ~]# cat script2
BEGIN{FS=":"}
{print $n}
[root@localhost ~]# awk -f script2 n=3 /etc/passwd
awk 'BEGIN{student["name"]="josen";student["num"]=48;student["age"]=18;print student["name"];print student["num"];print student["age"]}'
awk 'BEGIN{
var["a"]=1
var["b"]=2
var["c"]=3
for (s in var)
{print "Index:",s,"- Value:",var[s]}
}'
Index: a - Value: 1
Index: b - Value: 2
Index: c - Value: 3
[root@localhost ~]# awk -F ":" '$NF ~ /\/sbin\/nologin/{print $0}' /etc/passwd
[root@localhost ~]# awk -F ":" '$NF !~ /\/sbin\/nologin/{print $0}' /etc/passwd
数学表达式
除了正则,还可以用数学表达式,过滤如UID,GID寻找用户信息。
# 找出所有组ID为0的用户。
[root@chaogelinux ~]# awk -F : '$4==0{print $1}' /etc/passwd
root
sync
shutdown
halt
operator
常见的数学表达式
x == y:值x等于y。
x <= y:值x小于等于y。
x < y:值x小于y。
x >= y:值x大于等于y。
x > y:值x大于y。
例如找出uid大于1000的用户信息
[root@chaogelinux ~]# awk -F : '$3>1000{print $0}' /etc/passwd
yu1:x:1001:1004::/home/yu1:/bin/bash
yu2:x:1002:1002::/home/yu2:/bin/bash
pyyu:x:1500:1500::/home/pyyu:/bin/bash
tom:x:1501:1500::/home/tom:/bin/bash
jerry:x:1502:1502::/var/jerry:/sbin/nologin
eva:x:1503:1503:The girl eva userinfo:/home/eva:/bin/bash
mjj:x:1504:1504::/home/mjj:/bin/bash
xiaomage:x:1505:1505::/home/xiaomage:/bin/bash
pyyuc:x:2000:2000::/home/pyyuc:/bin/bash
alex:x:2001:1500::/home/alex:/bin/bash
virtual_chao:x:2003:2003::/var/ftpdir:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
cc:x:2004:2004::/home/cc:/bin/bash
only:x:2005:2005::/home/only:/bin/bash
test1:x:2006:2006::/home/test1:/bin/bash
chaoge:x:2007:2007::/home/chaoge:/bin/bash
chao:x:2008:2008::/home/chao:/bin/bash
susu:x:2009:2010::/home/susu:/bin/bash
Josen的小结
awk -F : '$4==1{print $1}' /etc/passwd
awk -F : '$4>1000{print $1,$NF}' /etc/passwd
结构化命令
awk也支持逻辑判断
if语句
awk支持标准的if语句
if (条件)
语句
案例,如果uid在1000,2000之间就打印出用户信息
[root@chaogelinux ~]# awk -F: '{if ($3 > 1000 && $3 < 2000)print $0}' /etc/passwd
yu1:x:1001:1004::/home/yu1:/bin/bash
yu2:x:1002:1002::/home/yu2:/bin/bash
pyyu:x:1500:1500::/home/pyyu:/bin/bash
tom:x:1501:1500::/home/tom:/bin/bash
jerry:x:1502:1502::/var/jerry:/sbin/nologin
eva:x:1503:1503:The girl eva userinfo:/home/eva:/bin/bash
mjj:x:1504:1504::/home/mjj:/bin/bash
xiaomage:x:1505:1505::/home/xiaomage:/bin/bash
执行多条语句
[root@chaogelinux ~]# cat data
10
5
13
50
34
[root@chaogelinux ~]#
[root@chaogelinux ~]#
[root@chaogelinux ~]#
[root@chaogelinux ~]#
[root@chaogelinux ~]# awk '{
> if ($1>20)
> {
> x=$1*2
> print x
> }
> }' data
100
68
if else
awk也支持if语句不成立,执行其他语句。
[root@chaogelinux ~]# awk '{
> if ($1 > 20)
> {x = $1 *2;print x}
> else {x=$1/2;print x}
> }' data
5
2.5
6.5
100
68
单行写法
单行写法,要注意分号;和花括号{}的使用。
[root@chaogelinux ~]# awk '{if($1>20) print $1*2;else print $1/2}' data
5
2.5
6.5
100
68
while语句
awk也支持while的循环功能。
语法
while (条件)
{
语句
}
while循环会遍历数据,且检查结束条件。
[root@chaogelinux ~]# cat data
130 120 135
160 113 140
145 170 215
# 该循环作用是相加三个列的值,求平均值
[root@chaogelinux ~]# awk '{
> total=0
> i=1
> while (i<4)
> {
> total+=$i
> i++
> }
> avg=total/3
> print "Average:",avg
> }' data
Average: 128.333
Average: 137.667
Average: 176.667
循环中断
awk支持在while循环里使用break和continue跳出循环。
[root@chaogelinux ~]# awk '{
> total=0
> i=1
> while (i<4)
> {
> total+=$i
> if (i==2)
> break
> i++
> }
> avg=total/2
> print "The average of the first tow data elements is:",avg
> }' data
The average of the first tow data elements is: 125
The average of the first tow data elements is: 136.5
The average of the first tow data elements is: 157.5
for循环
awk也支持for循环,且是c语言风格。
[root@chaogelinux ~]# awk '{
> total=0
> for (i=1;i<4;i++)
> {
> total+=$i
> }
> avg=total/3
> print "Average:",avg
> }' data
Average: 128.333
Average: 137.667
Average: 176.667
for循环的计数器比起while要好用了。
Josen的小结
awk中的普通变量是不需要加美元符的
#if语句
awk '{
> if ($1>20)
> {
> x=$1*2
> print x
> }
> }' data
awk '{if($1>20){x=$1*2;print x}}' data
awk -F : '{if ($3>1000 && $3<3000)print $0}' /etc/passwd
#if-else语句
awk '{
> if ($1 > 20)
> { x=$1*2;print x}
> else {x=$1/2;print x}
> }' data
awk '{if($1>20){x=$1*2;print x}else{x=$1/2;print x}}' data
#while循环
awk '{
> total=0
> i=1
> while(i<4)
> {
> total+=$i
> i++
> }
> avg=total/3
> print "Average:",avg
> }' data
awk '{total=0;i=1;while(i<4){total+=$i;i++} avg=total/3;print "Average:",avg}' data
#while循环-break
awk '{
> total=0
> i=1
> while(i<4)
> {
> total+=$i
> if(i==2)
> break
> i++
> }
> avg=total/2
> print "The average of the first tow data elements is:",avg
> }' data
awk '{total=0;i=1;while(i<4){total+=$i;if(i==2)break;i++}avg=total/2;print "1",avg}' data
#for循环
awk '{
> total=0
> for(i=1;i<4;i++)
> {
> total+=$i
> }
> avg=total/3
> print "Average:",avg
> }' data
awk '{total=0;for(i=1;i<4;i++){total+=$i}avg=total/3;print "Average:",avg}' data
awk内置函数
awk内置的函数功能非常强大,可以进行常见的数学,字符串等运算。
数学函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HsqP4b3x-1678373545849)(http://book.luffycity.com/linux-book/shell%E5%BC%80%E5%8F%91/pic/image-20201012155726978.png)]
int()函数用法,得到整数,如同其他编程语言的floor函数
floor函数,其功能是“向下取整”,或者说“向下舍入”、“向零取舍”,即取不大于x的最大整数,与“四舍五入”不同,下取整是直接取按照数轴上最接近要求值的左边值,即不大于要求值的最大的那个整数值。
Int()函数会生成值和0之间最接近该值整数。
例如int()函数值为5.6返回5,值为-5.6时取-5
rand()函数用于创建随机数,但是只会在0和1之间,要得到更大的数,就要放大返回值。
srand() 随机数种子,计算机无法产生绝对的随机数,生成只能是伪随机数,也就是根据某规则生成的,因此可以加入随机数种子,根据系统时间的变化,产生不同的随机数。
具体用法,注意随机数种子必须写在BEGIN里,这是awk的机制,我们必须在awk开始计算前,加入随机种子。
获取随机数,且判断,尝试多少次后,得到小于10的数
[root@chaogelinux ~]# awk -F "\t" 'BEGIN{
srand();
}{
value=int(rand()*100)
print value
if(value<=10)
print "值:"value"\t次数:"NR
}'
随机数简单写法
[root@chaogelinux ~]# awk 'BEGIN{srand();print rand()}'
0.547909
[root@chaogelinux ~]# awk 'BEGIN{srand();print rand()}'
0.999358
[root@chaogelinux ~]# awk 'BEGIN{srand();print int(100*rand())}'
29
[root@chaogelinux ~]# awk 'BEGIN{srand();print int(100*rand())}'
4
字符串函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O0XRJMBC-1678373545850)(http://book.luffycity.com/linux-book/shell%E5%BC%80%E5%8F%91/pic/image-20201012161422319.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LXucqZ9g-1678373545851)(http://book.luffycity.com/linux-book/shell%E5%BC%80%E5%8F%91/pic/image-20201012161432300.png)]
[root@chaogelinux sed_awk]# cat data.txt
This is an apple.
This is a boy.
This is a gril.
[root@chaogelinux sed_awk]#
[root@chaogelinux sed_awk]# awk '{print toupper($0)}' data.txt
THIS IS AN APPLE.
THIS IS A BOY.
THIS IS A GRIL.
函数使用案例
大写转换,统计长度
[root@chaogelinux ~]# awk 'BEGIN{x="chaoge";print toupper(x);print length(x)}'
CHAOGE
6
全局替换函数
[root@chaogelinux ~]# awk '
BEGIN{
str="Hello,chaoge"
print "替换前的字符串:",str
gsub("chaoge","超哥",str)
print "替换后的字符串: ",str
}'
替换前的字符串: Hello,chaoge
替换后的字符串: Hello,超哥
排序函数asort(),经过排序后的数组,索引会被重置
asort根据value进行排序
# 生成关联数组
[root@chaogelinux ~]# awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=22;for(i in t){print i,t[i]}}'
a 66
b 88
c 22
# asort()排序,新数组
[root@chaogelinux ~]# awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=22;asort(t,newt);for(i in newt){print i,newt[i]}}'
1 22
2 66
3 88
排序函数asorti(),排序的是索引
当关联数组的索引是字符串时,可以使用asorti()函数排序,如果是数字,直接for循环即可
# 当前关联数组
[root@chaogelinux ~]# awk 'BEGIN{t["z"]=66;t["q"]=88;t["a"]=3;for(i in t){print i,t[i]}}'
z 66
a 3
q 88
# 排序后
[root@chaogelinux ~]# awk 'BEGIN{t["z"]=66;t["q"]=88;t["a"]=3;\
> len=asorti(t,newt);\
> for(i=1;i<=len;i++){print i,newt[i]} }
> '
1 a
2 q
3 z
# 那么可以根据排序后的索引,对原关联数组再进行排序
[root@chaogelinux ~]# awk 'BEGIN{t["z"]=66;t["q"]=88;t["a"]=3;\
> len=asorti(t,newt);\
> for(i=1;i<=len;i++){print i,newt[i],t[newt[i]]}}'
1 a 3
2 q 88
3 z 66
时间函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tBl2CME-1678373545852)(http://book.luffycity.com/linux-book/shell%E5%BC%80%E5%8F%91/pic/image-20201012164052084.png)]
时间函数用在日志文件格式化处理非常有用。
[root@chaogelinux ~]# awk 'BEGIN{
> date=systime()
> day=strftime("%A,%B %d,%Y",date)
> print day
> }'
星期一,十月 12,2020
自定义函数
自定义函数
function name([variables])
{
语句
}
自定义函数必须写在awk最开始的地方。
定义awk脚本
[root@chaogelinux ~]# cat func.awk
function find_min(num1,num2)
{
if (num1<num2)
return num1
return num2
}
function find_max(num1,num2)
{
if (num1>num2)
return num1
return num2
}
function main(num1,num2)
{
# 找最小值
result=find_min(num1,num2)
print "最小值= ",result
# 找最大值
result=find_max(num1,num2)
print "最大值= ",result
}
BEGIN {
main(10,30)
}
# 执行
[root@chaogelinux ~]# awk -f func.awk
最小值= 10
最大值= 30
awk实践
现有一个数据文件,可以使用awk进行格式化数据处理。
[root@chaogelinux ~]# cat scores.txt
Rich Blum,team1,100,115,95
Barbara Blum,team1,110,115,100
Christine Bresnahan,team2,120,115,118
Tim Bresnahan,team2,125,112,116
对每只队伍的成绩排序,且计算总平均分
# 脚本
[root@chaogelinux ~]#
c[root@chaogelinux ~]# cat bowling.sh
#!/bin/bash
# for循环首先迭代出队名然后去重
for team in $(awk -F, '{print $2}' scores.txt|uniq)
do
# 循环内部计算,传递shell变量给awk
awk -v team=$team 'BEGIN{FS=",";total=0}
{
# 如果队名一致,就计算三场总分
if ($2==team)
{
total+=$3+$4+$5;
}
}
END {
# 求平均数
avg=total/6;
print "Total for",team,"is",total,",the average is ",avg
}' scores.txt
done
执行结果
[root@chaogelinux ~]# bash bowling.sh
Total for team1 is 635 ,the average is 105.833
Total for team2 is 706 ,the average is 117.667
Josen的小结
#srand()和rand()的用法
awk -F "\t" 'BEGIN{
> srand();
> }{
> value=int(rand()*100)
> print value
> if(value<=10)
> print "值:"value"\t次数:"NR
> }'
#生成随机数
awk 'BEGIN{srand();print int(rand()*100)}'
#大写切换
awk '{print toupper($0)}' data.txt
THIS IS AN APPLE.
THIS IS A BOY.
THIS IS A GRIL.
#长度统计
awk 'BEGIN{x="chaoge";print toupper(x);print length(x)}'
CHAOGE
6
#替换自定义变量的值的内容
awk '
> BEGIN{
> str="Hello.chaoge"
> print "替换前的字符串:",str
> gsub("chaoge","超哥",str)
> print "替换后的字符串:",str
> }'
> 替换前的字符串: Hello.chaoge
> 替换后的字符串: Hello.超哥
#根据数组的值排序,并重新生成数组
#生成原数组
awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=22;for(i in t){print i,t[i]}}'
a 66
b 88
c 22
#根据数组的值进行排序,新生成的数组
awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=22;asort(t,newt);for(i in newt){print i,newt[i]}}'
1 22
2 66
3 88
#根据数组的索引进行排序,生成新的数组
awk 'BEGIN{t["z"]=66;t["q"]=88;t["a"]=3;
len=asorti(t,newt);
for(i=1;i<=len;i++){print i,newt[i]} }
'
1 a
2 q
3 z