squirrel 脚本_Squirrel便携式Shell和脚本语言
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的语法非常稀疏,因此使用该语言编写代码会很快,尤其是如果您使用C
, C++
或任何更高级别的语言编写代码。
最好的是,此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
-collates在文件系统中的每个项目成其相应的插槽中。
此外,每个插槽都是一个数组,由两个语句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和脚本语言相关推荐
- shell脚本实战(第2版)/人民邮电出版社 脚本12 构建shell叫脚本库
首先,需要将用到的函数全部放入一个文件中,此文件命名为(library.sh) initailizeANSI() {esc=".033"blackf="${esc}[30 ...
- linux获取随机数脚本,Linux下对拍脚本与随机数生成器
对拍脚本 新建一个文档 check.sh 作为对拍脚本. #!/bin/bash while(true)do #死循环 ./data > .in #运行数据生成器,将数据输出到1.in ./st ...
- linux c语言乘法口诀,shell 脚本实现乘法口诀表的两种方法——shell与C语言
shell 脚本实现乘法口诀表的两种方法--shell与C语言 话不多说直接给出代码(执行c语言时没有gcc编译器会报错的哦!): 1 #!/bin/bash 2 if [ $# -eq 0 ] 3 ...
- lnmp shell安装脚本
LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构.LNMP是现在大多数大型公司在用的web环境,nginx小巧高效的web服务器和反向代理服务器,相对于apach占 ...
- linux Shell(脚本)编程入门实例讲解详解
linux Shell(脚本)编程入门实例讲解详解 为什么要进行shell编程 在Linux系统中,虽然有各种各样的图形化接口工具,但是sell仍然是一个非常灵活的工具.Shell不仅仅是命令的收集, ...
- linux脚本编写规则,shell脚本编写守则
现在centos7中使用的是bash软件,通过以下命令可以查看bash版本: [root@localhost ~]# cat /etc/redhat-release #查看系统的版本 CentOS L ...
- Linux之Shell管理脚本(一)
一:Shell的作用及常见种类: Shell是一个特殊的应用程序,他介于操作系统内核与用户之间,负责接受用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行.因此,Shell程序在系统 ...
- linux脚本编程教程,shell脚本编程基础教程
在Linux中,当你想要做什么事情的时候,可以通过输入命令传递给计算机,但也会有很多时候,我们需要计算机/服务器完成相同的任务,如果我们再一次一次输入命令执行的话,就会非常的不方便,要想让所有的事情变 ...
- linux脚本简介,Linux Shell脚本简介
Shell 诞生于 Unix,是与 Unix/Linux 交互的工具,单独地学习 Shell 是没有意义的,请先参考Unix/Linux入门教程,了解 Unix/Lunix 基础. 近几年来,Shel ...
最新文章
- HTML5新增了哪些标签
- PHP 实现代码复用的一个方法 traits新特性
- 安装完CentOS可以不做的事
- 【Linux系统编程】进程同步与互斥:System V 信号量
- windows下生成zlib1.dll
- Git 提示fatal: remote origin already exists 错误解决办法
- 启动列表的activity
- 【Python学习笔记】
- springMVC与RESTful支持
- C++练习 计算年份所属生肖
- Navicat:Access violation at address xxxxxxxxx in module 'navicat.exe'.Read of address xxxxxx
- <Java>设计一个名为Fan的类
- 基于51单片机数码管显示
- 腹有诗书气自华——记环宇通软CEO骆永华 1
- fa常用脚本,资产类表的字段详解
- php hook 键盘,python使用pyhook监控键盘并实现切换歌曲的功能
- 晶联讯1353显示屏测试程序
- java打印日志的几种方式
- linux权限管理详解
- robotstudio试用期延长总结
热门文章
- 【视觉SLAM之认识摄像头】
- matlab 随机整数函数,MATLAB的简单随机生成函数
- hexo主题编写(如何编写Hexo主题)
- stata 模型设定专题【计量经济系列(六)】(遗漏变量、无关变量、多重共线性、leverage、虚拟变量、线性插值......)
- 【SystemVerilog基础】合并数组与非合并数组深入探究
- CATIA 工程图制作视频教程 2D出图 标数教程
- 设计师与美工的素材网站
- (ECB,CBC)分组密码的算法类型及模式
- 如何知道发出的邮件对方有没有收到
- 妖精的尾巴等待服务器响应,《妖精的尾巴》数据互通注意事项