回到:


自定义函数示例

1.一次性读取一个文件所有数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function readfile(file    ,rs_bak,data){
rs_bak=RS
RS="^$"
if ( (getline data < file) < 0 ){
print "read file failed"
exit 1
}
close(file)
RS=rs_bak
return data
}


/^1/{
print $0
content = readfile("c.txt")
print content
}

将RS设置为^$是永远不可能出现的分隔符,除非这个文件为空文件。

2.重读文件

实现一个rewind()功能来重置文件偏移指针,从而模拟实现重读当前文件。

1
2
3
4
5
6
7
8
9
10
11
12
function rewind(    i){
# 将当前正在读取的文件添加到ARGV中当前文件的下一个元素
for(i=ARGC;i>ARCIND;i--){
ARGV[i] = ARGV[i-1]
}

# 随着增加ARGC,以便awk能够读取到因ARGV增加元素后的最后一个文件
ARGC++

# 直接进入下一个文件
nextfile
}

要注意可能出现无限递归的场景:

1
2
3
4
awk -f rewind.awk 'NR==3{rewind()}{print FILENAME, FNR, $0}' a.txt

# 下面这个会无限递归,因为FNR==3很可能每次重读时都会为真
awk -f rewind.awk 'FNR==3{rewind()}{print FILENAME, FNR, $0}' a.txt

3.格式化数组的输出

实现一个a2s()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BEGIN{
arr["zhangsan"]=21
arr["lisi"]=22
arr["wangwu"]=23
print a2s(arr)
}

function a2s(arr ,content,i,cnt){
for(i in arr){
if(cnt){
content=content""(sprintf("\t%s:%s\n",i,arr[i]))
} else {
content=content""(sprintf("\n\t%s:%s\n",i,arr[i]))
}
cnt++
}
return "{"content"}"
}

4.禁用命令行尾部的赋值语句

awk '{}' ./a=b a.txt中,a=b会被awk识别为变量赋值操作。但是,如果用户想要处理的正好是包含了等号的文件名,则应当去禁用该赋值操作。

禁用的方式很简单,只需为其加上一个路径前缀./即可。

为了方便控制,可通过-v设置一个flag类型的选项标记。

1
2
3
4
5
6
7
8
9
10
11
12
13
function disable_assigns(argc,argv,    i){
for(i=1;i<argc;i++){
if(argv[i] ~ /[[:alpha:]_][[:alnum:]_]*=.*/){
argv[i] = ("./"argv[i])
}
}
}

BEGIN{
if(assign_flag){
disable_assigns(ARGC,ARGV)
}
}

那么,调用awk时采用如下方式:

1
awk -v assign_flag=1 -f assigns.awk '{print}' a=b.txt a.txt