需要注意一点:由于对 reveal() 的调用是同一个函数中的最后一条语句,Squirrel 虚拟机(VM)— 运行脚本代码的引擎 — 可以通过称为尾递归(tail recursion)的技术将递归改为迭代 。实际上,尾递归消除了对递归使用调用栈的需要;因此,可以实现任意深度的递归并且可以避免栈溢出 。
Squirrel 的语法相当简单,因此使用这种语言编写代码非常快捷,特别是如果您曾经使用过 C、C或任何更高级的语言编写过代码的话,这一点则体现得更充分 。
最妙的是,这个 shell 代码是可移植的 。将它转移到 Windows 机器上,在其上安装 Squirrel Shell,然后就可以运行您的代码 。
改进表
与典型 shell 相比,Squirrel 的优秀特性之一就是它丰富的数据结构 。如果数据可以进行良好地组织,那么即使是复杂的问题通常也能够快速得到解决 。Squirrel 提供了真正的对象、异构数组和关联数组(在 Squirrel 中称为 表) 。
一个 Squirrel 表由一些 slot 或 (键-值)对组成 。除 Null 以外的任何值都可以充当一个键;任何值都可以被分配给一个 slot 。您将使用 “箭头 操作符创建一个新的 slot(<-) 。
让我们对 清单 2 的代码稍加改进,在将目录转变为任何子目录之前展示它的内容 。使用什么方法?使用一个本地表在单独的 slot 中存放文件和子目录,然后相应地处理两个类别 。清单 3 展示了新的代码 。
清单 3. 增强后的清单 2 将首先输出目录的内容,然后递归到子目录
#!/usr/bin/env squirrelsh
function reveal( filedir ) {
local tally = {};
tally[FILE] <- [];
tally[DIR] <- [];
if ( !exist( filedir ) ) {
return;
}
if ( filename( filedir ) == ".." || filename( filedir ) == "." ) {
return;
}
local names = readdir( filedir );
foreach( index, name in names ) {
tally[ filetype( name ) ].append( name ) ;
}
foreach( index, file in tally[FILE] ) {
printl( file );
}
foreach( index, dir in tally[DIR] ) {
printl( filename( dir )"/" );
}
foreach( index, dir in tally[DIR] ) {
reveal( dir );
}
}
local entrIEs = readdir( (__argc >= 2) ? __argv[1] : "." );
exit( 0 );
在这里非常适合使用表这种数据结构 。reveal() 中的表有两个 slot:一个用于文件,另一个用于目录 。filetype( name ) 函数的返回值 — 常量 FILE 或常量 DIR — 将文件系统中的每一项整理到相应的 slot 中 。
此外,每个 slot 是一个数组,由 tally[FILE] <- [] 和 tally[DIR] <- []; 这两条语句创建 。([] 是一个空数组) 。由于 tally 是函数内的本地变量,它将在每次调用时重新创建并清空范围,并且在每个调用被返回时自动销毁 。
数组函数 append( arg ) 将 arg 添加到数组的末尾,从而在此过程中形成了一个列表 。在执行完 foreach( index, name in names ) 循环后,所有项都被添加到这两个 slot 中其中一个的列表中 。函数其余部分的代码将输出文件,接着输出目录,然后是递归 。
当然,如果没有命令行参数的话,shell 脚本的价值就没有那么大了 。特殊 Squirrel Shell 变量 __argc 和 __argv 分别以字符串数组形式包含命令行参数的计数和参数列表 。根据约定,__argv[0] 始终都作为 shell 脚本的名称;因此,如果 __argc 的值至少为 2,那么将提供额外的参数 。为了简单起见,这个脚本只处理第一个额外参数 argv[1] 。
推荐阅读
- 跟踪 UNIX 应用程序的解决方案
- UNIX操作系统复杂的关机过程
- Unix文件名与Windows文件名的差异
- Unix中利用转义和引用来管理元字符
- 自动杀死Unix僵死的进程
- Unix操作系统中处理字符串问题的简单方式
- SCO unix三种安装BTLD的方式
- UNIX及SYBASE的安装
- 在Sco Unix下拨号上网
- 如何自动杀死UNIX僵死的进程