对话 UNIX: Squirrel--可移植的 shell 和脚本语言( 二 )


构建的结果是得到一个新的二进制文件,名为 squirrelsh 。假设此文件被安装到 PATH 变量的某个目录中,比如 /usr/local/bin,那么输入 squirrelsh 以启动该 shell 。在命令行提示符下,输入命令 printl(getenv("HOME")); 以输出主目录的路径:
$ squirrelsh 
> printl( getenv( "HOME" ) ); 
/home/strike 
> exit();
Squirrel Shell 基于 Squirrel 编程语言(参见 参考资料 获得更多信息的链接) 。该语言类似于 C,并且提供了非常类似于 Python 和 Ruby 等面向对象脚本语言的特性 。Squirrel Shell 纳入了 Squirrel 中的所有特性和数据类型,并添加了一些专门为常见 shell 脚本任务编写的新功能,比如复制文件和读取环境变量 。
尽管 Squirrel Shell 的语法对于日常的命令行使用过于繁杂 —echo $HOME 是和 Squirrel Shell 的 printl( "~") 具有等效功能的 Bash 命令 — 但是它拥有出色的脚本 。您只需要编写一次,就可以到处运行,而不需要针对 Unix 和 Windows 分别编写 。正如 Dinosaur 这样评价他的工作,“Squirrel Shell 主要是充当一个脚本翻译器 。
使用 Squirrel 编写脚本
让我们看一看一个 Squirrel Shell 脚本的示例 。清单 2 展示了文件 listing2.nut,此脚本将递归地列出您的主目录的内容 。
清单 2. listing2.nut
 
#!/usr/bin/env squirrelsh 
 
function reveal( filedir ) { 
 if ( !exist( filedir ) ) { 
return; 
 } 
 
 if ( filename( filedir ) == ".." || filename( filedir ) == "." ) { 
return; 
 } 
 
 if ( filetype( filedir ) == FILE ) { 
printl( filename( filedir, true ) ); 
return; 
 } 
 printl("Directory: "filename( filedir, true) ); 
 local names = readdir( filedir ); 
 foreach( index, name in names ) { 
reveal( name ); 
 } 
} 
 
local previous = getcwd(); 
 
chdir( "~" ); 
 
reveal( getcwd() ); 
 
chdir( previous ); 
 
exit( 0 );
按照规定,每个 shell 脚本的第一行将向操作系统表明要启动哪个程序来解释脚本 。通常,这一行会显示 #! /usr/bin/bash 或 #! /bin/zsh 以从某个位置启动特定 shell 或解释器 。
#!/usr/bin/env squirrelsh 有一些不同 。它启动了一个特殊的程序 env,此程序又启动 PATH 变量中找到的第一个 squirrelsh 实例 。因此,可以修改 PATH 变量以支持某个程序的本地版本 — 即您自己的、修改后的 squirrelsh 副本,位于 $HOME/bin/squirrelsh — 而不要修改 shell 脚本的内容 。
注意:这个技巧适用于所有解释器 。例如,#!/usr/bin/env ruby 将按照 PATH 设置的指示,调用您喜欢的 Ruby 版本 。总之,如果计划发布所编写的任何 shell 脚本,在第一行中使用 #!/usr/bin/env application 表单,因为它的 “移植性 更强:它将运行用户 在他/她的 PATH 变量中已经配置好的应用程序版本 。
清单 2 的其余部分应该比较熟悉,至少对于方法是这样 。函数 reveal() 是递归的:
如果为 reveal() 传递一个无效的路径或 “小圆点(.,当前目录)或 “两个小圆点(..,父目录),那么递归将结束 。
否则,如果参数 filedir 是一个文件,代码将输出其名称并返回,并再一次停止进一步的递归 。函数 filename() 可以接受一到两个参数 。如果只有一个参数,或者第二个参数为 false,那么将忽略扩展文件名 。如果提供 true 作为第二个参数,将返回完整的文件名 。
如果参数是一个目录,代码将输出其名称,然后扫描内容(不需要执行深度优先处理,因为目录内容并没有按特定的顺序排列 。下一个示例将改进输出) 。

推荐阅读