LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 259|回复: 0

精通awk系列(26):awk预定义函数(1):数值和字符串预定义函数

[复制链接]
发表于 2023-12-26 15:36:49 | 显示全部楼层 |阅读模式

awk预定义函数

预定义函数分为几类:

数值类内置函数
字符串类内置函数
时间类内置函数
位操作内置函数
数据类型相关内置函数:isarray()、typeof()
IO类内置函数:close()、system()、fflush()
awk数值类内置函数
int(expr)     截断为整数:int(123.45)和int("123abc")都返回123,int("a123")返回0
sqrt(expr)    返回平方根
rand()        返回[0,1)之间的随机数,默认使用srand(1)作为种子值
srand([expr]) 设置rand()种子值,省略参数时将取当前时间的epoch值(精确到秒的epoch)作为种子值
例如:

$ awk 'BEGIN{srand();print rand()}'
0.0379114
$ awk 'BEGIN{srand();print rand()}'
0.0779783
$ awk 'BEGIN{srand(2);print rand()}'
0.893104
$ awk 'BEGIN{srand(2);print rand()}'
0.893104
生成[10,100]之间的随机整数。

awk 'BEGIN{srand();print 10+int(91*rand())}'
awk字符串类内置函数
注意,awk中涉及到字符索引的函数,索引位都是从1开始计算,和其它语言从0开始不一样。

基本函数
sprintf(format, expression1, ...):返回格式化后的字符串,参考sprintf

a=sprintf("%s\n","abc")
length():返回字符串字符数量、数组元素数量、或数值转换为字符串后的字符数量

awk '
    BEGIN{
        print length(1.23)     # 4   # CONVFMT %.6g

        print 1.234567         # 1.23457
        print length(1.234567) # 7
        print length(122341223432.1213241234)  # 11
    }'
strtonum(str):将字符串转换为十进制数值

如果str以0开头,则将其识别为8进制
如果str以0x或0X开头,则将其识别为16进制
tolower(str):转换为小写

toupper(str):转换为大写

index(str,substr):从str中搜索substr(子串),返回搜索到的索引位置(索引从1开始),搜索不到则返回0

awk substr()
substr(string,start[,length]):从string中截取子串
start是截取的起始索引位(索引位从1开始而非0),length表示截取的子串长度。如果省略length,则表示从start开始截取剩余所有字符。

awk '
    BEGIN{
        str="abcdefgh"
        print substr(str,3)   # cdefgh
        print substr(str,3,3) # cde
    }
'
如果start值小于1,则将其看作为1对待,如果start大于字符串的长度,则返回空字符串。

如果length小于或等于0,则返回空字符串。

awk split()和patsplit()
split(string, array [, fieldsep [, seps ] ]):将字符串分割后保存到数组array中,数组索引从1开始存储。并返回分割得到的元素个数
其中fieldsep指定分隔符,可以是正则表达式方式的。如果不指定该参数,则默认使用FS作为分隔符,而FS的默认值又是空格。

seps是一个数组,保存了每次分割时的分隔符。

例如:

split("abc-def-gho-pq",arr,"-",seps)
其返回值为4。同时得到的数组a和seps为:

arr[1] = "abc"
arr[2] = "def"
arr[3] = "gho"
arr[4] = "pq"

seps[1] = "-"
seps[2] = "-"
seps[3] = "-"
split在开始工作时,会先清空数组,所以,将split的string参数设置为空,可以用于清空数组。

awk 'BEGIN{arr[1]=1;split("",arr);print length(arr)}'  # 0
如果分隔符无法匹配字符串,则整个字符串当作一个数组元素保存到数组array中。

awk 'BEGIN{split("abcde",arr,"-");print arr[1]}' # abcde
patsplit(string, array [, fieldpat [, seps ] ]):用正则表达式fieldpat匹配字符串string,将所有匹配成功的部分保存到数组array中,数组索引从1开始存储。返回值是array的元素个数,即匹配成功了多少次
如果省略fieldpat,则默认采用预定义变量FPAT的值。

awk '
    BEGIN{
        patsplit("abcde",arr,"[a-z]")
        print arr[1]   # a
        print arr[2]   # b
        print arr[3]   # c
        print arr[4]   # d
        print arr[5]   # e
    }
'
awk match()
match(string,reg[,arr]):使用reg匹配string,返回匹配成功的索引位(从1开始计数),匹配失败则返回0。如果指定了arr参数,则arr[0]保存的是匹配成功的字符串,arr[1]、arr[2]、…保存的是各个分组捕获的内容
match匹配时,同时会设置两个预定义变量:RSTART和RLENGTH

匹配成功时:
RSTART赋值为匹配成功的索引位,从1开始计数
RLENGTH赋值为匹配成功的字符长度
匹配失败时:
RSTART赋值为0
RLENGTH赋值为-1
例如:

awk '
    BEGIN{
        where = match("foooobazbarrrr","(fo+).*(bar*)",arr)
        print where   # 1
        print arr[0]  # foooobazbarrrr
        print arr[1]  # foooo
        print arr[2]  # barrrr
        print RSTART  # 1
        print RLENGTH # 14
    }
'
因为match()匹配成功时返回值为非0,而匹配失败时返回值为0,所以可以直接当作条件判断:

awk '
  {
    if(match($0,/A[a-z]+/,arr)){
      print NR " : " arr[0]
    }
  }
' a.txt
awk sub()和gsub()
sub(regexp, replacement [, target])
gsub(regexp, replacement [, target]):sub()的全局模式
sub()从字符串target中进行正则匹配,并使用replacement对第一次匹配成功的部分进行替换,替换后保存回target中。返回替换成功的次数,即0或1。

target必须是一个可以赋值的变量名、$N或数组元素名,以便用它来保存替换成功后的结果。不能是字符串字面量,因为它无法保存数据。

如果省略target,则默认使用$0。

需要注意的是,如果省略target,或者target是$N,那么替换成功后将会使用OFS重新计算$0。

awk '
    BEGIN{
        str="water water everywhere"
        #how_many = sub(/at/, "ith", str)
        how_many = gsub(/at/, "ith", str)
        print how_many   # 1
        print str        # wither water everywhere
    }
'
在replacement参数中,可以使用一个特殊的符号&来引用匹配成功的部分。注意sub()和gsub()不能在replacement中使用反向引用\N。

awk '
    BEGIN{
        str = "daabaaa"
        gsub(/a+/,"C&C",str)
        print str  # dCaaCbaaa
    }
'
如果想要在replacement中使用&纯字符,则转义即可。

sub(/a+/,"C\\&C",str)
两根反斜线:
因为awk在正则开始工作时,首先会扫描所有awk代码然后编译成awk的内部格式,扫描期间会解析反斜线转义,使得\\变成一根反斜线。当真正开始运行后,sub()又要解析,这时\&才表示的是对&做转义。
扫描代码阶段称为词法解析阶段,运行解析阶段称为运行时解析阶段。

awk gensub()
gawk支持的gensub(),完全可以取代sub()和gsub()。

gensub(regexp, replacement, how [, target]):
可以替代sub()和gsub()。

how指定替换第几个匹配,例如指定为1表示只替换第一个匹配。此外,还可以指定为g或G开头的字符串,表示全局替换。

gensub()返回替换后得到的结果,而target不变,如果匹配失败,则返回target。这和sub()、gsub()不一样,sub()、gsub()返回的是替换成功的次数。

gensub()的replacement部分可以使用\N来引用分组匹配的结果,而sub()、gsub()不允许使用反向引用。而且,gensub()在replacement部分也还可以使用&或\0来表示匹配的整个结果。

awk 'BEGIN{
    a = "abc def"
    b = gensub(/(.+) (.*)/, "\\2 \\1, \\0 , &", "g", a)
    print b  # def abc, abc def , abc def
}'
awk asort()和asorti()
asort(src,[dest [,how]])
asorti(src,[dest [,how]])
asort对数组src的值进行排序,然后将排序后的值的索引改为1、2、3、4…序列。返回src中的元素个数,它可以当作排序后的索引最大值。

asorti对数组src的索引进行排序,然后将排序后的索引值的索引改为1、2、3、4…序列。返回src中的元素个数,它可以当作排序后的索引最大值。

arr["last"] = "de"
arr["first"] = "sac"
arr["middle"] = "cul"
asort(arr)得到:

arr[1] = "cul"
arr[2] = "de"
arr[3] = "sac"
asorti(arr)得到:

arr[1] = "first"
arr[2] = "last"
arr[3] = "middle"
如果指定dest,则将原始数组src备份到dest,然后对dest进行排序,而src保持不变。

how参数用于指定排序时的方式,其值指定方式和PROCINFO["sorted_in"]一致:可以是预定义的排序函数,也可以是用户自定义的排序函数。参考指定数组遍历顺序。


文章链接: https://www.junmajinlong.com/shell/awk/awk_builtin_function1/
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表