目录
awk用许多内置函数,包括算术函数、字符串函数、输入输出函数、时间函数、位操作函数等,awk也支持自定义函数。
算术函数
函数 |
功能 |
atan2(y, x) |
返回 y/x 的反正切,其值在-π到π之间 |
cos(x) |
返回 x 的余弦 |
sin(x) |
返回 x 的正弦 |
exp(x) |
返回 e 的 x 次幂 |
log(x) |
返回 x 的以 e 为底自然对数 |
sqrt(x) |
返回 x 平方根 |
int(x) |
返回 x 的整数部分的值 |
rand() |
返回任意数字 n,其中 0 <= n < 1 |
srand([x]) |
将 rand 函数的种子值设置为 X 参数的值,或如果省略 X 参数则使用当天的时间;返回先前的种子值 |
# awk '
BEGIN { print atan2(0,-1)
print exp(1)
print 100/3
print int(100/3)
print rand()
print rand()
srand()
print rand()
print rand()
} '
3.14159
2.71828
33.3333
33
0.237788
0.291066
0.503071
0.44804
示例1:指定范围内随机数的生成
传递一个参数,输出一个改参数范围内的一个随机整数
# vim lotto1.sh
awk -v TOPNUM=$1 '
BEGIN {
srand()
select = 1 + int(rand() * TOPNUM)
print select
}'
执行结果如下:
# sh lotto1.sh 123
117
# sh lotto1.sh 123
51
# sh lotto1.sh 123
97
示例2:指定范围内生成指定个数的随机数
传递2个参数,第一个参数生成的个数,第二个是随机数的范围
# cat lotto2.sh
awk -v NUM=$1 -v TOPNUM=$2 '
BEGIN {
if (NUM<=0)
NUM=6
if (TOPNUM<=0)
TOPNUM=30
printf("Pick %d of %d\n",NUM,TOPNUM)
srand()
for(j=1;j<=NUM;j++){
do{
select=1+int(rand()*TOPNUM)
}while(select in pick)
pick[select]=select
}
for(j in pick)
printf("%s ",pick[j])
printf("\n")
}'
执行结果如下:
# sh lotto2.sh 5 89
Pick 5 of 89
35 47 31 1 42
# sh lotto2.sh 3 189
Pick 3 of 189
73 169 145
字符串函数
函数 |
功能 |
asort(source [, dest [, how ] ]) |
按照value值对source数组进行排序,同时会将数组的index值替换为数字,数字是以1开始排序,该方法返回source的元素个数 |
asorti(source [, dest [, how ] ]) |
和asort类似,只是排序是按照source的index值进行排序 |
gensub(regexp, replacement, how [, target]) |
用replacement替换由regexp在目标字符串target中匹配出的字符串,how指定替换匹配出的第几个字符串,如果how是'g'或'G'开头的字符串,表示替换所有匹配出的字符串;如果不指定target,则使用$0;该方法返回替换后的字符串 |
gsub(regexp, replacement [, target]) |
功能基本同gensub,只是没有how参数,也就是gsub会替换所有匹配出的字符串;该方法返回替换的字符串个数 |
index(in, find) |
在find字符串中查找in字符串,返回in第一次出现的位置 |
length([string]) |
返回字符串的长度,如果没有指定string,默认使用$0 |
match(string, regexp [, array]) |
在string中匹配regexp,如果匹配成功返回匹配的位置,否则返回0;这个方法会修改系统变量RSTART和RLENGTH的值,其中RSTART是匹配字符串的起始位置,RLENGTH是匹配字符串的长度 |
patsplit(string, array [, fieldpat [, seps ] ]) |
|
split(string, array [, fieldsep [, seps ] ]) |
切分字符串string,将切分的字符串放入到array中,fieldsep指定分隔符,如果不指定分隔符使用FS的值,seps用以存储array[i]与array[i+1]之间的分隔符;该方法返回array的元素个数 |
sprintf(format, expression1, ...) |
返回printf以相同参数打印出的字符串。 |
strtonum(str) |
检查str并返回它的十进制数值,如果str以0开头,则将str看做8进制数,如果string以‘0x’或‘0X’开头,则将str看做十六进制数 |
sub(regexp, replacement [, target]) |
功能和gsub类似,但是sub只替换匹配到的第一个字符串,其返回值是0(没有匹配到)或者1 |
substr(string, start [, length ]) |
返回从string中获取从start开始长度为length的子串,如果不指定length,则获取从start到string末尾的子串 |
tolower(string) |
将string中大写字母转换为小写并返回新串 |
toupper(string) |
将string中小写字母转换为大写并返回新串 |
示例
asort()、asorti()
# gawk 'BEGIN{
> a["last"]="de"
> a["first"]="sac"
> a["middle"]="cul"
> asort(a)
> for(i in a)
> print "a["i"] = " a[i]
> }'
a[1] = cul
a[2] = de
a[3] = sac
# gawk 'BEGIN{
> a["last"]="de"
> a["first"]="sac"
> a["middle"]="cul"
> asorti(a)
> for(i in a)
> print "a["i"] = " a[i]
> }'
a[1] = first
a[2] = last
a[3] = middle
上述例子中asort方法只有一个参数,程序它就会修改数组a的内容,如果有两个参数,它会将source数组排序的结果写入到dest数组中,如下:
# gawk 'BEGIN{
> a["last"]="de"
> a["first"]="sac"
> a["middle"]="cul"
> asort(a,b)
> for(i in a)
> print "a["i"] = " a[i]
> print "-----------"
> for(i in b)
> print "b["i"] = " b[i]
> }'
a[first] = sac
a[middle] = cul
a[last] = de
-----------
b[1] = cul
b[2] = de
b[3] = sac
gensub() 、 gsub() 、sub()
# gawk 'BEGIN{
> a = "Hello World"
> b = gensub(/(.+) (.+)/, "\\2 \\1", "g", a)
> print b
> }'
World Hello
# echo a b c a b c a b c | gawk '{ print gensub(/a/, "hadoop", 2) }'
a b c hadoop b c a b c
# echo a b c a b c a b c | gawk '{ print gensub(/a/, "hadoop", "ggg") }'
hadoop b c hadoop b c hadoop b c
# echo a b c a b c a b c | gawk '{ gsub(/a/, "hadoop") ;print}'
hadoop b c hadoop b c hadoop b c
# echo a b c a b c a b c | gawk '{ sub(/a/, "hadoop") ;print}'
hadoop b c a b c a b c
从上面的例子中可以看出gensub对替换的控制粒度是最强的。
下面看一个有意思的示例:
# awk 'BEGIN {
> str = "daabaaa"
> sub(/a+/, "C&C", str)
> print str
> }'
dCaaCbaaa
# awk 'BEGIN {
str = "daabaaa"
gsub(/a+/, "C&C", str)
print str
}'
dCaaCbCaaaC
仔细看上面的示例,发现在第二参数有个字符 &,该字符用以表示需要在第一个参数中指定的字符串。
index()
# awk 'BEGIN { print index("peanut", "an") }'
3
length()
# awk 'BEGIN { print length("peanut") }'
6
# awk 'BEGIN { print length(25*5) }'
3
上面例子中,有个计算25*5字符串的长度,首先会计算25*5的结果,是125,然后将125转换为字符串“125”,再计算器长度。结果是3
match()
假设字段中有多个冒号“:”,现在需要将第二冒号替换为中横线 "-":
下面分别是输入文件内容和脚本内容:
# cat test1
1234:2134:::hello
4341:45::09:world
# cat test1.awk
match($1,/:[^:]*:/){
before=substr($1,1,(RSTART+RLENGTH-2))
after=substr($1,(RSTART+RLENGTH))
$1=before "-" after
print $1
}
执行结果如下:
# awk -f test1.awk test1
1234:2134-::hello
4341:45-:09:world
split()
# awk 'BEGIN {
> str = "cul-de-sac"
> split(str,a,"-",seps)
> for(i in a)
> print "a["i"] = " a[i]
> for(i in seps)
> print "seps["i"] = " seps[i]
> }'
a[1] = cul
a[2] = de
a[3] = sac
seps[1] = -
seps[2] = -
sprintf()
# awk 'BEGIN {
> pival = sprintf("pi = %.2f (approx.)", 22/7)
> print pival
> }'
pi = 3.14 (approx.)
strtonum()
# echo 0x11 | gawk '{ printf "%d\n", strtonum($1) }'
17
# echo 0123 | gawk '{ printf "%d\n", strtonum($1) }'
83
# echo abc | gawk '{ printf "%d\n", strtonum($1) }'
0
substr()
# awk 'BEGIN {
print substr("707-555-1111",6)
print substr("707-555-1111",6,2)
}'
55-1111
55
tolower(),toupper()
# cat user
user1 78 98 90 84
user2 89 75 47 99
user3 74 83 92 78
# awk '{printf("<%s>,<%s>\n",tolower($0),toupper($0))}' user
<user1 78 98 90 84>,<USER1 78 98 90 84>
<user2 89 75 47 99>,<USER2 89 75 47 99>
<user3 74 83 92 78>,<USER3 74 83 92 78>
输入输出函数
system()函数
system()函数执行一个以表达式方式给出的命令。然而,它的命令没有产生可供程序处理的输出。它返回被执行命令的退出状态。
如下示例,创建一个目录,第一次会执行成功,第二次执行失败:
# awk '
> BEGIN {
> if(system("mkdir dir")!=0)
> print "Command Failed"
> }'
# ls dir
# awk '
BEGIN {
if(system("mkdir dir")!=0)
print "Command Failed"
}'
mkdir: cannot create directory ‘dir’: File exists
Command Failed
时间函数
函数 |
功能 |
mktime(datespec [, utc-flag ]) |
用于将时间字符串转换为时间戳格式,参数datespec的格式是 "YYYY MM DD HH MM SS [DST]",如果给定格式不正确或者缺少信息,将会返回-1 |
strftime([format [, timestamp [, utc-flag] ] ]) |
用于将时间戳转换为指定格式的时间字符串,参数format默认值是"%a %b %e %H:%M:%S %Z %Y",格式和命令 date 的默认输出是一样的 |
systime() |
返回从1970年1月1日开始到当前时间(不计闰年)的整秒数 |
示例
mktime(datespec [, utc-flag ])
# gawk 'BEGIN{print mktime("2018 10 25 12 34 23")}'
1540442063
# gawk 'BEGIN{print mktime("2018 10 25 12 34 ")}'
-1
# gawk 'BEGIN{print mktime("2018-10-25 12:34:23")}'
-1
strftime([format [, timestamp [, utc-flag] ] ])
# gawk 'BEGIN{print strftime()}'
Thu Nov 15 10:38:03 CST 2018
# gawk 'BEGIN{print strftime("%Y-%m-%d %H:%M:%S")}'
2018-11-15 11:16:11
systime()
# gawk 'BEGIN{print systime()}'
1542249087
位操作函数
函数 |
功能 |
and(v1, v2 [, ...]) |
返回与值 |
compl(val) |
返回val的位补 |
lshift(val, count) |
返回val左移count位后的值 |
or(v1, v2 [, ...]) |
返回或值 |
rshift(val, count) |
返回val右移count位后的值 |
xor(v1, v2 [, ...]) |
返回异或值 |
示例
# gawk 'BEGIN{print compl(12)}'
9007199254740979
# gawk 'BEGIN{print and(12,0)}'
0
# gawk 'BEGIN{print or(12,0)}'
12
# gawk 'BEGIN{print rshift(12,1)}'
6
# gawk 'BEGIN{print lshift(12,1)}'
24
# gawk 'BEGIN{print xor(12,0)}'
12
# gawk 'BEGIN{print xor(12,12)}'
0
其他函数
isarray(x) : 判断x是否是一个数组,是返回1,否则返回0
示例
# awk 'BEGIN {
str = "cul-de-sac"
split(str,a,"-",seps)
print isarray(str)
}'
0
# awk 'BEGIN {
str = "cul-de-sac"
split(str,a,"-",seps)
print isarray(a)
}'
1
自定义函数
自定义函数的语法定义如下:
function name([parameter-list])
{
body-of-function
}
parameter-list 是用逗号分隔的变量列表
示例
function insert(string,pos,ins){
before_tmp=substr(string,1,pos)
after_tmp=substr(string,pos+1)
return before_tmp ins after_tmp
}
上面函数insert有三个参数,函数的功能是在字符串string的pos配置插入另一个字符串ins。执行如下:
# vim test2.awk
function insert(string,pos,ins){
before_tmp=substr(string,1,pos)
after_tmp=substr(string,pos+1)
return before_tmp ins after_tmp
}
match($1,/:[^:]*:/){
$1=insert($1,RSTART+RLENGTH+1,"XXXX")
print $1
}
# awk -f test2.awk test1
1234:2134:::XXXXhello
4341:45::0XXXX9:world
需要说明的是在函数体中定义的变量默认为全局变量。对于上面的insert()函数,临时变量before_tmp和after_tmp在函数外是可见的,如下:
# vim test2.awk
function insert(string,pos,ins){
before_tmp=substr(string,1,pos)
after_tmp=substr(string,pos+1)
return before_tmp ins after_tmp
}
match($1,/:[^:]*:/){
$1=insert($1,RSTART+RLENGTH+1,"XXXX")
print before_tmp
print after_tmp
print $1
}
# awk -f test2.awk test1
1234:2134:::
hello
1234:2134:::XXXXhello
4341:45::0
9:world
4341:45::0XXXX9:world
上述程序在主程序中打印了insert函数中的临时变量,可见临时变量在函数外部也是可见的。为了解决这个问题,可以将临时变量放在参数列表的末尾。如果想使得上面insert函数中的before_tmp和after_tmp变为局部变量,可以按照如下定义insert函数:
function insert(string,pos,ins,before_tmp,after_tmp){
before_tmp=substr(string,1,pos)
after_tmp=substr(string,pos+1)
return before_tmp ins after_tmp
}