awk内置函数
算数函数
最常用的算数函数有rand函数、srand函数、int函数。
可以使用rand函数生成随机数,但是使用rand函数时,需要配合srand函数,否则rand函数返回的值将一直不变,示例如下。
[root@server01 ~]# awk 'BEGIN{print rand()}' 0.237788 [root@server01 ~]# awk 'BEGIN{print rand()}' 0.237788 [root@server01 ~]# awk 'BEGIN{print rand()}' 0.237788
可以看到,如果单纯的使用rand函数,生成的值是不变的,可以配合srand函数,生成一个大于0小于1的随机数,示例如下
[root@server01 ~]# awk 'BEGIN{srand();print rand()}' 0.881739 [root@server01 ~]# awk 'BEGIN{srand();print rand()}' 0.419895 [root@server01 ~]# awk 'BEGIN{srand();print rand()}' 0.352016
可以看到,上例中生成的随机数都是小于1的小数,如果我们想要生成整数随机数,可以将上述生成的随机数乘以100,然后截取整数部分,使用int函数可以截取整数部分的值,示例如下
[root@server01 ~]# awk 'BEGIN{srand();print rand()}' 0.222916 [root@server01 ~]# awk 'BEGIN{srand();print 100*rand()}' 66.5736 [root@server01 ~]# awk 'BEGIN{srand();print int(100*rand())}' 58 [root@server01 ~]# awk 'BEGIN{srand();print int(100*rand())}' 59 [root@server01 ~]# awk 'BEGIN{srand();print int(100*rand())}' 10 [root@server01 ~]# awk 'BEGIN{srand();print int(100*rand())}' 48 [root@server01 ~]#
经过上述处理以后,可以得到一个小于100的随机整数。
字符串函数
我们可以使用gsub函数或sub函数替换某些文本,先来 看看gsub函数怎样使用。
如果我们想要将如下文本中的第一列中的小写字母"l"都替换成大写字母"L",则可以使用gsub函数,示例如下。
[root@server01 ~]# cat test11
Allen Phillips
Green Lee
William Ken Allen
[root@server01 ~]# awk '{gsub("l","L",$1);print $0}' test11
ALLen Phillips
Green Lee
WiLLiam Ken Allen
如上图所示,我们使用gsub函数,将小写字母"l"替换成大写字母"L",但是替换的范围只限于"$1",所以,当我们再次输出文本时,发现只有文本中的第一列中的小写字母"l"被替换成了大写字母"L",其他列中的小写字母"l"并未被替换,当然,如果你想要替换文本中所有的小写字母"l",则可以将上图中的"$1"换成"$0",或者省略gsub函数中的第三个参数,省略gsub中的第三个参数时,默认为"$0",示例如下。
[root@server01 ~]# awk '{gsub("l","L");print $0}' test11 ALLen PhiLLips Green Lee WiLLiam Ken ALLen [root@server01 ~]# awk '{gsub("l","L",$0);print $0}' test11 ALLen PhiLLips Green Lee WiLLiam Ken ALLen
看完上述示例,我想你应该已经明白了gsub函数的作用,没错,gsub函数会在指定范围内查找指定的字符,并将其替换为指定的字符串。
其实,我们还可以根据正则表达式,替换字符串,示例如下。
[root@server01 ~]# awk '{gsub("[a-z]","6",$1);print $0}' test11 A6666 Phillips G6666 Lee W666666 Ken Allen
那么sub函数与gsub函数有什么不同呢?我们来对比一下。
[root@server01 ~]# awk '{gsub("l","L",$1);print $0}' test11 ALLen Phillips Green Lee WiLLiam Ken Allen [root@server01 ~]# awk '{sub("l","L",$1);print $0}' test11 ALlen Phillips Green Lee WiLliam Ken Allen
细心如你一定已经发现了,当使用gsub函数时,gsub会替换指定范围内的所有符合条件的字符。
而使用sub函数则不同,当使用sub函数时,sub函数只会替换指定范围内第一次匹配到的符合条件的字符。
我们可以把gsub函数的作用理解为指定范围内的全局替换。
可以把sub函数的作用理解为指定范围内的单次替换,只替换第一次匹配到的字符。
这就是sub函数与gsub函数的为唯一的不同之处。
我们可以通过length函数,获取到指定字符串的长度,示例如下
[root@server01 ~]# awk '{for(i=1;i<=NF;i++){print $i,length($i)}}' test11 Allen 5 Phillips 8 Green 5 Lee 3 William 7 Ken 3 Allen 5
如上例所示,我们输出了文本中每个单词的长度,其实,length函数可以省略传入的参数,即不指定任何字符换,当省略参数时,默认使用"$0"作为参数,示例如下。
[root@server01 ~]# awk '{print $0,length()}' test11 Allen Phillips 14 Green Lee 9 William Ken Allen 17
正如上例假所示,我们使用length函数,获取到了文本中每一行的长度。
我们可以使用index函数,获取到指定字符位于整个字符串中的位置,示例如下
[root@server01 ~]# awk '{print index($0,"Lee")}' test11 0 7 0
上例中,我们使用index函数,在每一行中咋找字符串"Lee",如果Lee存在于当前行,则返回字符串Lee位于当前行的位置,如果Lee不存在于当前行,则返回0,表示当前行并不存在Lee,如上图所示,第二行中包含Lee,而且Lee位于第二行的第7个字符的位置,所以返回数字7。
在前文中,我们在总结数组时,提到过一个函数,借助这个函数可以动态的生成数组,而不用手动的设置数组中每个元素的值,没错,这个函数就是split函数。通过split函数,我们可以将指定的字符串按照指定的分割符切割,将切割后的每一段赋值到数组的元素中,从而动态的创建数组,示例如下。
[root@server01 ~]# awk -v ts="大娃:二娃:三娃" 'BEGIN{split(ts,huluwa,":");for(i in huluwa){print huluwa[i]}}' 大娃 二娃 三娃
如上例所示,我们通过split函数,将字符串ts切割了,以":"作为分割符,将分割后的字符串保存到了名为huluwa的数组中,当我们输出数组中的元素时,每个元素的值为分割后的字符,其实,split函数也有对应的返回值,其返回值就是分割以后的数组长度,示例如下。
[root@server01 ~]# awk -v ts="大娃:二娃:三娃" 'BEGIN{print split(ts,huluwa,":")}' 3
注意,被split函数分割后的数组的元素下标从1开始,不像其他语言中的数组下标是从0开始的,而且数组中元素输出的顺序可能与字符串中字符的顺序不同,原因在前文中已经说过了,如果我们想要按照顺序输出数组中的元素,可以使用如下方法。
[root@server01 ~]# awk -v ts="qq te ab th" 'BEGIN{split(ts,arr," ");for(i in arr){print arr[i]}}' th qq te ab
[root@server01 ~]# awk -v ts="qq te ab th" 'BEGIN{arrlen=split(ts,arr," ");for(i=1;i<=arrlen;i++){print i,arr[i]}}' 1 qq 2 te 3 ab 4 th
我们先使用了split函数生成了数组,并且将split的返回值保存在变量arrlen中,然后利用for循环中变量的递增,顺序的输出了数组中的对应下标以及元素值,如果你不明白为什么,请参考前文。
其他函数
我们还能够通过asort函数根据元素的值进行排序,但是,经过asort函数排序过后的数组的下标将会被重置,示例如下
[root@server01 ~]# awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=3;for(i in t){print i,t[i]}}' a 66 b 88 c 3 [root@server01 ~]# awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=3;asort(t);for(i in t){print i,t[i]}}' 1 3 2 66 3 88
如上例所示,数组中元素的值均为数字,但是下标为自定义的字符串,通过asort函数对数组排序后,再次输出数组中的元素时,已经按照元素的值的大小进行了排序,但是,数组的下标也被重置为了纯数字,其实,asort还有一种用法,就是在对原数组元素值排序的同时,创建一个新的数组,将排序后的元素放置在新数组中,这样能够保持原数组不做任何改变,我们只要打印新数组中的元素值,即可输出排序后的元素值,示例如下。
[root@server01 ~]# awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=3;asort(t,newt);for(i in t){print i,t[i]}}' a 66 b 88 c 3 [root@server01 ~]# awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=3;asort(t,newt);for(i in newt){print i,newt[i]}}' 1 3 2 66 3 88
其实,asort函数也有返回值,它的返回值就是数组的长度,换句话说,asort的返回值就是数组中元素的数量,示例如下。
[root@server01 ~]# awk 'BEGIN{t["a"]=66;t["b"]=88;t["c"]=3;len=asort(t,newt);for(i=1;i<=len;i++){print i,newt[i]}}' 1 3 2 66 3 88
理解完asort 函数,我们来认识一下asorti 函数,仔细看,是 asort 与 asorti
使用asort 函数可以根据元素的值进行排序,而使用asorti 函数可以根据元素的下标进行排序。
当元素的下标为字符串时,我们可以使用asorti 函数,根据下标的字母顺序进行排序,当元素的下标为数字时,我们就没有必要使用函数排序了,直接使用for循环即可排序,所以,此刻我们只考虑数组的下标为字符串时,怎样通过asorti 函数根据下标对数组进行排序。
当数组的下标为字符串时,asorti 函数会根据原数组中的下标的字母顺序进行排序,并且将排序后的下标放置到一个新的数组中,并且asorti函数会返回新的数组的长度,示例如下
[root@server01 ~]# 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@server01 ~]# 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
如上例所示,asorti 函数根据数组t的下标排序后,创建了一个新的数组newt,newt中元素的值即为t数组下标的值,上例中,我们使用len变量保存了asorti函数的返回值,并且输出了最后排序后的新数组。
那么,聪明如你,一定想到了,既然我们已经将t数组的下标排序输出了,那么我们一定可以根据排序后的下标再次输出对应的元素值,从而达到根据数组下标排序后,输出原数组元素的目的,示例如下。
[root@server01 ~]# 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
上述过程,其实就是新数组负责排序老数组的下标,并将排序后的下标作为新数组的元素,而我们输出新数组元素的同时,又将新数组的元素值作为老数组下标,从而输出了老数组中的元素值,这句话好绕
[root@server01 ~]# awk '{gsub("[a-z]","6",$1);print $0}' test11A6666 PhillipsG6666 LeeW666666 Ken Allen