【译】 AWK教程指南 11递归程序
awk 中除了函数的参数列表(Argument List)上的参数(Arguments)外,所有变量不管于何处出现,全被视为全局变量。其生命持续至程序结束——该变量不论在function外或 function内皆可使用,只要变量名称相同所使用的就是同一个变量,直到程序结束。因递归函数内部的变量,会因它调用子函数(本身)而重复使用,故编写该类函数时应特别留心。
例如:执行
awk '
BEGIN {
x =
y =
test_variable( x )
printf("Return to main : arg1= %d, x= %d, y= %d, z= %d\n", arg1, x, y, z)
}
function test_variable( arg1 )
{
arg1++ # arg1 为参数列上的参数, 是local variable. 离开此函数后将消失.
y++ # 会改变主式中的变量 y
z = # z 为该函数中新使用的变量, 主程序中变量 z 仍可被使用.
printf("Inside the function: arg1=%d, x=%d, y=%d, z=%d\n", arg1, x, y, z)
} '
结果屏幕打印出

由上可知:
- 函数内可任意使用主程序中的任何变量。
- 函数内所启用的任何变量(除参数外),于该函数之外依然可以使用。
此特性优劣参半,最大的坏处是程序中的变量不易被保护,特别是递归调用本身,执行子函数时会破坏父函数内的变量。
一个变通的方法是:在函数的参数列中虚列一些参数。函数执行中使用这些虚列的参数来记录不想被破坏的数据,如此执行子函数时就不会破坏到这些数据。此外awk 并不会检查调用函数时所传递的参数个数是否一致。
例如:定义递归函数如下:
function demo( arg1 ) { # 最常见的错误例子
........
for(i=; i< ; i++){
demo(x)
# 又调用本身. 因为 i 是 global variable, 故执行完该子函数后
# 原函数中的 i 已经被坏, 故本函数无法正确执行.
.......
}
..........
}
可将上列函数中的 i 虚列在该函数的参数列上,如此 i 便是一个局部变量,不会因执行子函数而被破坏。
将上列函数修改如下:
function demo( arg1, i ) {
......
for(i=; i< ; i++) {
demo(x) #awk不会检查呼叫函数时, 所传递的参数个数是否一致
.....
}
}
$0, $1,.., NF, NR,..也都是 global variable,读者于递归函数中若有使用这些内置变量,也应另外设立一些局部变量来保存,以免被破坏。
范例:以下是一个常见的递归调用范例。它要求使用者输入一串元素(各元素间用空白隔开) 然后打印出这些元素所有可能的排列。
编辑如下的awk程序,取名为 permu
awk '
BEGIN {
print "请输入排列的元素,各元素间请用空白隔开"
getline
permutation($, "")
printf("\n共 %d 种排列方式\n", counter)
}
function permutation( main_lst, buffer, new_main_lst, nf, i, j )
{
$ = main_lst # 把main_lst指定给$0之后awk将自动进行字段分割.
nf = NF # 故可用 NF 表示 main_lst 上存在的元素个数.
# BASE CASE : 当main_lst只有一个元素时.
if( nf == ){
print buffer main_lst #buffer的内容再加上main_lst就是完成一次排列的结果
counter++
return
}
# General Case : 每次从 main_lst 中取出一个元素放到buffer中
# 再用 main_lst 中剩下的元素 (new_main_lst) 往下进行排列
else for( i=; i<=nf ;i++)
{
$ = main_lst # $0为全局变量已被破坏, 故重新把main_lst赋给$0,令awk再做一次字段分割
new_main_lst = ""
for(j=; j<=nf; j++) # 连接 new_main_lst
if( j != i )
new_main_lst = new_main_lst " " $j
permutation( new_main_lst, buffer " " $i )
}
}
' $*
执行
$ ./permu
屏幕上出现提示信息,若输入 1 2 3 回车,结果打印出:

说明:
1. 有些较旧版的awk,并不容许使用者指定$0的值。此时可改用gawk 或 nawk。否则也可自行使用 split() 函数来分割 main_lst。
2. 为避免执行子函数时破坏 new_main_lst, nf, i, j 故把这些变量也列于参数列上。如此,new_main_lst, nf, i, j 将被当成局部变量,而不会受到子函数中同名的变量影响。读者声明函数时,参数列上不妨将这些 "虚列的参数" 与真正用于传递信息的参数间以较长的空白隔开,以便于区别。
3. awk 中欲将字符串concatenation(连接)时,直接将两字符串并置即可(Implicit Operator)。
例如:
awk '
BEGIN{
A = "This "
B = "is a "
C = A B "key." # 变量A与B之间应留空白,否则"AB"将代表另一新变量.
print C
} '
结果将印出

4. awk使用者所编写的函数可再重用,并不需要每个awk式中都重新编写。
将函数部分单独编写于一文件中,当需要用到该函数时再以下列方式include进来。
$ awk -f 函数文件名 -f awk主程序文件名 数据文件文件名
【译】 AWK教程指南 11递归程序的更多相关文章
- 【译】 AWK教程指南
前面的话: 这几天写了一个程序,在同一个目录里生成了很多文件,需要统计其中部分文件的总大小,发现经常用到的ls.du等命令都无济于事,我甚至都想到了最笨的方法,写一个脚本:mkdir一个新目录,把要统 ...
- 【译】 AWK教程指南 1前言
前面的话: 这几天写了一个程序,在同一个目录里生成了很多文件,需要统计其中部分文件的总大小,发现经常用到的ls.du等命令都无济于事,我甚至都想到了最笨的方法,写一个脚本:mkdir一个新目录,把要统 ...
- 【译】 AWK教程指南 7AWK应用实例
本节将示范一个统计上班到达时间及迟到次数的程序. 这程序每日被执行时将读入两个数据文件: * 员工当日到班时间的数据文件 ( 如下列的 arr.dat ) * 存放员工当月迟到累计次数的文件 当程序执 ...
- 【译】 AWK教程指南 2概述
2.1 为什么用AWK 由于awk具有上述特色,在问题处理的过程中,可轻易使用awk来撰写一些小工具:这些小工具并非用来解决整个大问题,它们只扮演解决个别问题过程的某些角色,可通过Shell所提供的p ...
- 【译】 AWK教程指南 10编写可与用户交互的AWK程序
执行awk程序时,awk会自动从文件中读取数据来进行处理,直到文件结束.只要将awk读取数据的来源改成键盘输入,便可设计与awk 交互的程序.本节将提供一个该类程序的范例. 范例:本节将编写一个英语生 ...
- 【译】 AWK教程指南 6在AWK程序中使用Shell命令
awk程序中允许调用Shell指令,并提供管道解决awk与系统间数据传递的问题.所以awk很容易使用系统资源,读者可利用这个特点来编写某些适用的系统工具. 范例:写一个awk程序来打印出线上人数. 将 ...
- 【译】 AWK教程指南 附录E-正则表达式
为什么要使用正则表达式 UNIX 中提供了许多 指令 和 tools,它们具有在文件中 查找(Search)字串或替换(Replace)字串 的功能.像 grep, vi , sed, awk,... ...
- 【译】 AWK教程指南 附录D-AWK的内置变量
因内置变量的个数不多,此处按其相关性分类说明,并未按其字母顺序排列. ARGC ARGC表示命令行上除了选项 -F, -v, -f 及其所对应的参数之外的所有参数的个数.若将"awk程序&q ...
- 【译】 AWK教程指南 附录C-AWK的内建函数
C.1 字串函数 index( 原字串, 查找的子字串 ) 若原字串中含有欲寻找的子字串,则返回该子字串在原字串中第一次出现的位置,若未曾出现该子字串则返回0. 例如: $ awk 'BEGIN{ p ...
随机推荐
- 1025: [SCOI2009]游戏 - BZOJ
Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对 ...
- Binary search for the first element greater than target
We all know how to search through an array for an element whose value equals the target value, but h ...
- jquery下拉列表选中项改变时获取新选项的属性值
$("#textSel").change(funtion(){ var selVal=$(this).val(); var selText=$("#textSel opt ...
- 团体程序设计天梯赛-练习集L2-011. 玩转二叉树
L2-011. 玩转二叉树 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜 ...
- uva 624
背包问题 总时间为容量,单个唱片时间为各个物体的价值与体积 f[] 用来记录路径 #include <cstdio> #include <cstring> #define ...
- Kafka server的的停止
这算是CountDownLatch的一个典型使用场景. kafka.Kafka对象的main方法中与此有关的代码为 // attach shutdown handler to catch contro ...
- iOS设计模式——委托(delegate)
委托(delegate)也叫代理是iOS开发中常用的设计模式.我们借助于protocol(参考博文:objective-c协议(protocol))可以很方便的实现这种设计模式. 什么是代理? 苹果的 ...
- SGU128 Snake
SGU128,题意是给定N个点,问说能不能形成一个闭环G,要求G经过每个点,且在每个点处都有90度的转角,且不能出现自交. 没想出来,通过这提供的思路,由于每个点处都需要90度的转弯,因此每个点处必然 ...
- 启用了不安全的HTTP方法
安全风险: 可能会在Web 服务器上上载.修改或删除Web 页面.脚本和文件. 可能原因: Web 服务器或应用程序服务器是以不安全的方式配置的. 修订建议: 如果 ...
- node.js模块之fs文件系统
fs 模块是文件操作的封装,它提供了文件的读取.写入.更名.删除.遍历目录.链接等 POSIX 文件系统操作.与其他模块不同的是,fs 模块中所有的操作都提供了异步的和同步的两个版本, 例如读取文件内 ...