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

回到:


awk预定义函数

预定义函数分为几类:

  • 数值类内置函数
  • 字符串类内置函数
  • 时间类内置函数
  • 位操作内置函数
  • 数据类型相关内置函数:isarray()、typeof()
  • IO类内置函数:close()、system()、fflush()

awk数值类内置函数

1
2
3
4
int(expr)     截断为整数:int(123.45)和int("123abc")都返回123,int("a123")返回0
sqrt(expr) 返回平方根
rand() 返回[0,1)之间的随机数,默认使用srand(1)作为种子值
srand([expr]) 设置rand()种子值,省略参数时将取当前时间的epoch值(精确到秒的epoch)作为种子值

例如:

1
2
3
4
5
6
7
8
$ 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]之间的随机整数。

1
awk 'BEGIN{srand();print 10+int(91*rand())}'

awk字符串类内置函数

注意,awk中涉及到字符索引的函数,索引位都是从1开始计算,和其它语言从0开始不一样。

基本函数

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    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开始截取剩余所有字符。

1
2
3
4
5
6
7
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是一个数组,保存了每次分割时的分隔符。

例如:

1
split("abc-def-gho-pq",arr,"-",seps)

其返回值为4。同时得到的数组a和seps为:

1
2
3
4
5
6
7
8
arr[1] = "abc"
arr[2] = "def"
arr[3] = "gho"
arr[4] = "pq"

seps[1] = "-"
seps[2] = "-"
seps[3] = "-"

split在开始工作时,会先清空数组,所以,将split的string参数设置为空,可以用于清空数组。

1
awk 'BEGIN{arr[1]=1;split("",arr);print length(arr)}'  # 0

如果分隔符无法匹配字符串,则整个字符串当作一个数组元素保存到数组array中。

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

如果省略fieldpat,则默认采用预定义变量FPAT的值。

1
2
3
4
5
6
7
8
9
10
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

例如:

1
2
3
4
5
6
7
8
9
10
11
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,所以可以直接当作条件判断:

1
2
3
4
5
6
7
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

1
2
3
4
5
6
7
8
9
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

1
2
3
4
5
6
7
awk '
BEGIN{
str = "daabaaa"
gsub(/a+/,"C&C",str)
print str # dCaaCbaaa
}
'

如果想要在replacement中使用&纯字符,则转义即可。

1
sub(/a+/,"C\\&C",str)

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

awk gensub()

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

  • gensub(regexp, replacement, how [, target])

可以替代sub()和gsub()。

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

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

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

1
2
3
4
5
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中的元素个数,它可以当作排序后的索引最大值。

1
2
3
arr["last"] = "de"
arr["first"] = "sac"
arr["middle"] = "cul"

asort(arr)得到:

1
2
3
arr[1] = "cul"
arr[2] = "de"
arr[3] = "sac"

asorti(arr)得到:

1
2
3
arr[1] = "first"
arr[2] = "last"
arr[3] = "middle"

如果指定dest,则将原始数组src备份到dest,然后对dest进行排序,而src保持不变。

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

文章作者: 骏马金龙
文章链接: http://www.junmajinlong.com/shell/awk/awk_builtin_function1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 骏马金龙
打赏我