1799年,一位法国陆军工程师做出了惊人的发现。 不,不是鹅肝,卡门培尔奶酪,巴氏杀菌法或萨特法,而是罗斯塔石,这是解密埃及大部分古代象形文字的关键(参见图1)。

图1. Rosetta石头,一种1100英镑的三语税收政策。 碑文是对神职人员减税的公告。 (Hans Hillewaert信用2007)

这块石头建于公元前196年,刻有一个段落的三种译本-每种用象形文字,Demotic(埃及文字)和古典希腊语。 通过比较翻译,或将短语从一种翻译映射到另一种,罗塞塔石碑揭示了许多曾经难以理解的字形的含义。

换句话说,将Rosetta石头视为半吨重的Babelfish。 即使在公元前196年,也有不止一种方式来发表讲话。

2000年后,软件开发人员面临着类似的问题。 在这么多的编程语言中,有很多方法可以说同一件事。 即使在命令行中,也有许多类似物可供选择,包括各种外壳和各种命令组合。

一般来说,品种不错,但也可能令人生畏。 您选择哪种解决方案? 技术会跟上需求的步伐吗? 投入的时间和精力会有所回报吗? 还是那些整洁的字形(或那些Perl的标志?)会过时? 更糟糕的是,是否需要为其他环境翻译( 重写 )所有内容?

如果您不想使用Fish Shell,Bash Shell,Z Shell,Windows操作系统的cmd.exe或某些其他Shell脚本语言的特性,请尝试Squirrel Shell。 Squirrel Shell提供了一种先进的,面向对象的脚本语言,该语言在UNIX,Linux,Mac OS X和Windows系统中同样有效。 您可以编写一次脚本,然后在任何地方运行。

更好的是,您不必在耳朵上放半吨的石头即可使用它。

捉松鼠

Squirrel Shell随时可用,并且根据GNU公共许可证版本3(GPLv3)的条款免费使用。 最新版本是1.2.2,日期为2008年10月11日。Squirrel Shell的创始人和维护者是Constantin“ Dinosaur” Makshin。

Squirrel Shell的下载页面(请参阅参考资料中的链接)提供了32位和64位Windows的源代码和二进制文件。 如果使用UNIX或Linux,请检查发行版的存储库中是否有合适的二进制文件,或者从头开始构建Squirrel Shell。

从头开始构建非常简单。 下载并解压缩源tarball,转到源目录,并增加清单1所示的相当典型的构建拼写。

清单1.从源代码构建Squirrel Shell
$ ./configure --with-pcre=system && make && sudo make install
Checking CPU architecture...   x86
Checking for install...   /usr/bin/install
...
Configuration has been completed successfully.Build for x86 CPU architectureInstallation prefix: /usr/localAllow debugging: noBuild static librariesUse system PCRE 6.7 libraryInstall MIME information: autoCreate symbolic link: noCompile C code with 'gcc'Compile C++ code with 'g++'Create static libraries with 'ar rc'Create executables and shared libraries with 'g++'Install files with 'install'

要查找用于配置的特定于软件包的选项的列表,请在命令行中键入./configure --help

为方便起见,Squirrel Shell捆绑了Perl兼容正则表达式(PCRE)库的源代码,该库在程序中广泛使用。 如果您的系统缺少PCRE,则捆绑的代码可使构建变得快速而简单。 但是,如果您的系统已经具有PCRE,则可以通过指定--with-pcre=system选项来选择使用它。 否则,指定--with-pcre=auto链接到系统库或Squirrel Shell副本的较新版本。

构建的结果是一个新的二进制文件,恰当地命名为squirrelsh。 假设二进制文件安装在PATH变量的目录中,例如/ usr / local / bin,则键入squirrelsh启动外壳程序。 在命令提示符下,键入命令printl(getenv("HOME")); 打印主目录的路径:

$ squirrelsh
> printl( getenv( "HOME" ) );
/home/strike
> exit();

Squirrel Shell基于Squirrel编程语言( 有关更多信息的链接,请参阅参考资料 )。 该语言类似于C++ ,并提供类似于Python和Ruby等面向对象的脚本语言的功能。 Squirrel Shell包含了Squirrel中的所有功能和数据类型,并添加了许多专门为常见的Shell脚本编写任务而编写的新功能,例如复制文件和读取环境变量。

尽管Squirrel Shell的语法在日常工作中过于冗长,但命令行使用printl( "~") echo $HOME是Squirrel Shell的printl( "~")的Bash等效项-它在脚本中printl( "~")用。 您只需编写一次,就可以在任何地方运行,而不能在UNIX中一次编写,而在Windows中则需要编写一次。 正如恐龙在谈到自己的作品时所说的:“松鼠壳主要是脚本解释器。”

用松鼠编写脚本

让我们看一个示例Squirrel Shell脚本。 清单2显示了文件listing2.nut,这是一个递归列出主目录内容的脚本。

清单2. listing2.nut
#!/usr/bin/env squirrelshfunction 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 #! /usr/bin/bash#! /bin/zsh 该行上的#! /bin/zsh可以从特定位置启动特定的Shell或解释器。

A#!/usr/bin/env squirrelsh有点不同。 它启动一个特殊程序env,该程序又启动在PATH变量中找到的squirrelsh的第一个实例。 因此,您可以更改PATH变量以支持某些程序的本地版本(例如,您自己的修改后的squirrelsh副本在$ HOME / bin / squirrelsh中),而无需更改shell脚本的内容。

注意:此技巧适用于各种口译员。 例如,根据您的PATH设置, #!/usr/bin/env ruby将调用您首选的Ruby版本。 通常,如果您打算分发编写的所有Shell脚本,请在第一行中使用#!/usr/bin/env application表单,因为它更“便于携带”:它将运行用户在其中配置的应用程序的版本他或她的PATH变量。

清单2的其余部分应该看起来很熟悉,至少在方法上是这样。 函数reveal()是递归的:

  • 如果您传递了reveal()无效的路径或多年生的“点”( . ,当前目录)或“点。”( .. ,父目录),则递归结束。
  • 否则,如果参数filedir是文件,则代码将打印其名称并返回,再次中止进一步的递归。 函数filename()可以使用一个或两个参数。 使用一个参数或第二个参数为false ,将省略文件名的扩展名。 如果提供true作为第二个参数,则返回整个文件名。
  • 如果参数是目录,则代码将打印其名称,然后扫描其内容。 (该处理不一定是深度优先的,因为目录的内容不是按特殊顺序排序的。下一个示例改进了输出。)

一件令人感兴趣的事情:因为对reveal()的调用是该函数中的最后一条语句,因此Squirrel虚拟机(VM)(运行脚本代码的引擎)可以通过称为尾部递归的技术将递归转换为迭代。 本质上,尾递归消除了调用堆栈的使用。 因此,可以进行任意深度的递归并避免堆栈溢出。

Squirrel的语法非常稀疏,因此使用该语言编写代码会很快,尤其是如果您使用CC++或任何更高级别的语言编写代码。

最好的是,此shell代码是可移植的。 将其传输到Windows计算机,安装Windows的Squirrel Shell,然后运行您的代码。

摆弄桌子

Squirrel的一个不错的功能是相对于典型Shell而言,它丰富的数据结构集。 如果可以很好地组织数据,则通常可以快速解决复杂的问题。 Squirrel具有真实的对象,异构数组和关联数组(或表,用Squirrel说)。

Squirrel表由插槽或(键/值)对组成。 除Null外的任何值都可以用作键; 可以将任何值分配给插槽。 使用“箭头”运算符( <- )创建一个新插槽。

让我们改进清单2中的代码,以显示目录的内容,然后再深入到任何子目录。 该方法? 使用本地表在单独的插槽中累积文件和子目录,然后相应地处理这两个类别。 清单3显示了新版本的代码。

清单3.清单2的增强版本,它首先打印目录的内容,然后递归到子目录中
#!/usr/bin/env squirrelshfunction 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()的表有两个插槽:一个用于文件,一个用于目录。 该函数的返回值filetype( name ) -或者恒定FILE或恒定DIR -collat​​es在文件系统中的每个项目成其相应的插槽中。

此外,每个插槽都是一个数组,由两个语句tally[FILE] <- []tally[DIR] <- []; 。 ( []是一个空数组。)因为tally是函数内的局部变量,所以每次调用都会重新创建tally ,它会超出范围,并在每次调用返回时自动销毁。

数组函数append( arg )arg添加到数组的末尾,从而在进程中累积一个列表。 在循环foreach( index, name in names ) ,每一项都已放入一个插槽的列表中。 在函数中找到的其余代码将先打印文件,然后目录,然后递归。

当然,如果没有命令行参数,shell脚本将毫无价值。 特殊的Squirrel Shell变量__argc__argv包含命令行参数的计数和作为字符串数组的参数列表。 同样,根据约定, __argv[0]始终是外壳程序脚本的名称; 因此,如果__argc至少为2,则提供了其他参数。 为简便起见,此脚本仅处理第一个额外的参数argv[1]

作为参考, 清单4显示了一个与清单3在功能上相同的Ruby脚本(由Makshin先生编写)。尽管Ruby简洁,但仍不如Squirrel Shell代码那么简洁。

清单4. Ruby中清单3的重新实现
!/usr/bin/ruby# List directory contents.path = ARGV[0] == nil ? "." : ARGV[0].dup# Remove trailing slashes
while path =~ /\/$/path.chop!
endentries = Dir.open(path)
for entry in entriesunless entry == "." || entry == ".."filePath    = "#{path}/#{entry}"fileStat = File.stat(filePath)if fileStat.directory?puts "dir : #{filePath}"elsif fileStat.file?puts "file: #{filePath}"endend
endentries.close()

有关Squirrel语言的详细信息,请参见《 Squirrel编程语言参考》 ( 有关链接,请参阅参考资料 )。

巧妙地,Squirrel Shell中的几乎所有功能都抽象了底层操作系统的细节,因此您的代码可以尽可能通用。 例如, filename()函数(在上面的前两个清单中使用)将文件路径名中的前导路径剥离filename()例如,将/home/example/some/directory/file.txt减少为file.txt)您在什么平台上。 类似地, readdir()filetype()允许您对真实的,基础的操作系统和文件系统的机密和陷阱一无所知。 通常,常规外壳程序不提供此类抽象。 (更高级的脚本语言可以。)

其他有用的,独立convpath()平台的函数包括convpath()将路径名转换为本机路径名格式,以及run()调用另一个可执行文件。 convpath()函数是双向的,在编写跨平台脚本时非常有用。

主要是正则表达式

Shell脚本通常用于自动执行系统管理和维护工作。 这种自动操作背后的强大功能是正则表达式 ,这是一组真正的象形文字,用于查找,匹配和分解字符串。 如开头所述,Squirrel Shell需要PCRE库,该库也可以在Perl,PHP,Ruby和许多其他解释器和程序中找到。 PCRE是数据切片器和切块机的武士刀。

尽管十分完善,但Squirrel Shell的正则表达式实现还是有些不同,可能会使您想起PHP的实现。 要在Squirrel Shell中使用正则表达式,请定义正则表达式,对其进行编译,进行比较,然后对结果进行迭代(如果有)。

清单5显示了一个示例程序,该程序演示了Squirrel Shell中的正则表达式(该代码由Makshin先生编写,并经许可使用)。

清单5. Squirrel Shell中的正则表达式演示
#!/usr/bin/env squirrelsh// Match a regular expression against textprint("Text: ");
local text = scan();print("Pattern: ");
local pattern = scan();local re = regcompile(pattern);
if (!re)
{printl("Failed to compile regular expression - " + regerror());exit(1);
}local matches = regmatch(re, text);
if (!matches)
{printl("Failed to match regular expression - " + regerror());regfree(re);exit(1);
}regfree(re);
printl("Matches found:");
foreach (match in matches)printl("\t\"" + substr(text, match[0], match[1]) + "\"");

在这里, scan()从标准输入中读取一些文本和模式,尽管没有通常界定正则表达式开始和结束的前导和尾部斜杠( / )字符。

给定一个模式,函数reqgcompile()编译该模式,从而加快重复匹配的速度。 您可以使用reqgcompile()函数的标志(等效于PCRE /i修饰符)来启用或禁用区分大小写,并且可以将一行与另一行进行匹配以使用另一选项(与PCRE /m选项等效)。 如果不编译正则表达式,则所有匹配都将失败。

regmatch(re, text)函数将正则表达式与文本进行比较,生成无匹配项的Null或整数对数组(双元素数组)。 任何一对中的第一个整数是比赛的开始; 第二个整数是比赛的结尾。 这解释了代码的最后一行中substr(text, match[0], match[1])的用法。

执行比较后,可以遍历结果。 如果在任何时候不再需要编译后的正则表达式,请使用regfree() 。 还有一个regfreeall()函数,用于处理所有已编译表达式所拥有的所有资源。

松鼠壳的螺母

在理想的情况下,相同的编程逻辑将适用于UNIX,Linux和Windows,并且程序员即使没有更高的生产力也会更加快乐。 operating,操作系统有所不同,有时您必须诉诸特定系统的自定义代码。

在那些既不能使用Squirrel Shell也不可以抽象平台的情况下,Squirrel Shell提供了一种方便的功能来探测操作系统,因此代码可以遵循适当的分支。

清单6显示了如何使用platform()函数进行决策。 尽管此函数可能是unknown值,但它始终会返回一个值。

清单6. platform()函数产生操作系统的类型
print( "Made by ... ");local platform = platform();switch ( platform ) {case "linux":printl( "Linus." );break;case "macintosh":printl( "Steve." );break;case "win32":case "win64":printl( "Bill." );break;default:printl( "Unknown" );
}

您还可以通过Squirrel Shell环境变量PLATFORM查找当前平台的类型:

> printl( PLATFORM );
linux

环境变量CPU_ARCH产生编译了外壳程序的处理器:

> printl( CPU_ARCH );
x86

啊,疯了!

Squirrel Shell函数的其余部分管理文件,操纵环境和执行数学运算。 确实,三角函数有近20个内置函数。 现在正在计划2.0版,它将包括更多类,对Unicode的支持,改进的交互模式以及模块化的插件体系结构。

松鼠壳不是交互式壳,但这没关系。 该类别中已经有许多替代品。 松鼠壳作为脚本运行者要好得多。 它的数据结构比传统的shell更有能力,它的语法很熟悉,其底层虚拟引擎支持从枚举类型到线程的所有内容。 Squirrel引擎也很小,不到6000行代码。 您甚至可以将所有Squirrel嵌入到另一个应用程序中。

当您必须为两个平台编写代码时,请尝试使用Squirrel Shell。 它的坚果将帮助您保持健康。


翻译自: https://www.ibm.com/developerworks/aix/library/au-spunix_squirrel/index.html

squirrel 脚本_Squirrel便携式Shell和脚本语言相关推荐

  1. shell脚本实战(第2版)/人民邮电出版社 脚本12 构建shell叫脚本库

    首先,需要将用到的函数全部放入一个文件中,此文件命名为(library.sh) initailizeANSI() {esc=".033"blackf="${esc}[30 ...

  2. linux获取随机数脚本,Linux下对拍脚本与随机数生成器

    对拍脚本 新建一个文档 check.sh 作为对拍脚本. #!/bin/bash while(true)do #死循环 ./data > .in #运行数据生成器,将数据输出到1.in ./st ...

  3. linux c语言乘法口诀,shell 脚本实现乘法口诀表的两种方法——shell与C语言

    shell 脚本实现乘法口诀表的两种方法--shell与C语言 话不多说直接给出代码(执行c语言时没有gcc编译器会报错的哦!): 1 #!/bin/bash 2 if [ $# -eq 0 ] 3 ...

  4. lnmp shell安装脚本

    LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构.LNMP是现在大多数大型公司在用的web环境,nginx小巧高效的web服务器和反向代理服务器,相对于apach占 ...

  5. linux Shell(脚本)编程入门实例讲解详解

    linux Shell(脚本)编程入门实例讲解详解 为什么要进行shell编程 在Linux系统中,虽然有各种各样的图形化接口工具,但是sell仍然是一个非常灵活的工具.Shell不仅仅是命令的收集, ...

  6. linux脚本编写规则,shell脚本编写守则

    现在centos7中使用的是bash软件,通过以下命令可以查看bash版本: [root@localhost ~]# cat /etc/redhat-release #查看系统的版本 CentOS L ...

  7. Linux之Shell管理脚本(一)

    一:Shell的作用及常见种类: Shell是一个特殊的应用程序,他介于操作系统内核与用户之间,负责接受用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行.因此,Shell程序在系统 ...

  8. linux脚本编程教程,shell脚本编程基础教程

    在Linux中,当你想要做什么事情的时候,可以通过输入命令传递给计算机,但也会有很多时候,我们需要计算机/服务器完成相同的任务,如果我们再一次一次输入命令执行的话,就会非常的不方便,要想让所有的事情变 ...

  9. linux脚本简介,Linux Shell脚本简介

    Shell 诞生于 Unix,是与 Unix/Linux 交互的工具,单独地学习 Shell 是没有意义的,请先参考Unix/Linux入门教程,了解 Unix/Lunix 基础. 近几年来,Shel ...

最新文章

  1. HTML5新增了哪些标签
  2. PHP 实现代码复用的一个方法 traits新特性
  3. 安装完CentOS可以不做的事
  4. 【Linux系统编程】进程同步与互斥:System V 信号量
  5. windows下生成zlib1.dll
  6. Git 提示fatal: remote origin already exists 错误解决办法
  7. 启动列表的activity
  8. 【Python学习笔记】
  9. springMVC与RESTful支持
  10. C++练习 计算年份所属生肖
  11. Navicat:Access violation at address xxxxxxxxx in module 'navicat.exe'.Read of address xxxxxx
  12. <Java>设计一个名为Fan的类
  13. 基于51单片机数码管显示
  14. 腹有诗书气自华——记环宇通软CEO骆永华 1
  15. fa常用脚本,资产类表的字段详解
  16. php hook 键盘,python使用pyhook监控键盘并实现切换歌曲的功能
  17. 晶联讯1353显示屏测试程序
  18. java打印日志的几种方式
  19. linux权限管理详解
  20. robotstudio试用期延长总结

热门文章

  1. 【视觉SLAM之认识摄像头】
  2. matlab 随机整数函数,MATLAB的简单随机生成函数
  3. hexo主题编写(如何编写Hexo主题)
  4. stata 模型设定专题【计量经济系列(六)】(遗漏变量、无关变量、多重共线性、leverage、虚拟变量、线性插值......)
  5. 【SystemVerilog基础】合并数组与非合并数组深入探究
  6. CATIA 工程图制作视频教程 2D出图 标数教程
  7. 设计师与美工的素材网站
  8. (ECB,CBC)分组密码的算法类型及模式
  9. 如何知道发出的邮件对方有没有收到
  10. 妖精的尾巴等待服务器响应,《妖精的尾巴》数据互通注意事项