Rob*_*cio 43 shell scripting bash architecture
前言:我喜欢 bash 并且无意开始任何形式的争论或圣战,希望这不是一个非常幼稚的问题。
这个问题与超级用户上的这篇文章有些相关,但我认为 OP 并不真正知道他在问什么。我在 FreeBSD、linux、OS X 和 Windows 上的 cygwin 上使用 bash。我最近在 Windows 上使用 PowerShell 也有丰富的经验。
是否有用于 *nix 的 shell,已经可用或正在开发中,它与 bash 兼容,但在混合中添加了一层面向对象的脚本?我所知道的唯一接近的是 python 控制台,但据我所知,它不提供对标准 shell 环境的访问。例如,我不能只是cd ~and ls,然后chmod +x file在 python 控制台中。我将不得不使用 python 来执行这些任务,而不是标准的 unix 二进制文件,或者使用 python 代码调用二进制文件。
这样的壳存在吗?
Gil*_*il' 46
我可以想到 shell 中的三个理想特性:
Unix shell 倾向于专注于交互方面,并将大部分系统访问和一些编程分包给外部工具,例如:
ftp 用于 FTPmail, Mail,mailx等用于基本电子邮件cron 用于计划任务dbus-*或qdbus)(包括现代桌面环境,如 KDE?4)通过使用正确的参数或管道输入调用命令,可以完成很多很多事情。这是一种非常强大的方法——每个任务最好有一个工具可以很好地完成它,而不是一个程序可以完成所有事情但很糟糕——但它确实有其局限性。
unix shell 的一个主要限制,我怀疑这就是您对“面向对象的脚本”要求所追求的,是它们不擅长将信息从一个命令保留到下一个命令,或者以更奇特的方式组合命令一个管道。特别是,程序间通信是基于文本的,因此应用程序只有在以兼容的方式序列化其数据时才能组合。这既是福也是祸:一切都是文本的方法可以轻松快速地完成简单的任务,但为更复杂的任务增加了障碍。
交互式可用性也与程序可维护性背道而驰。交互式程序应该很短,需要很少的引用,不要用变量声明或打字等来打扰你。 可维护的程序应该是可读的(所以没有很多缩写),应该是可读的(所以你不必怀疑一个词是字符串、函数名、变量名等),应该有一致性检查,如变量声明和类型等。
总之,shell 是一个难以达成的妥协。好的,到此结束咆哮部分,进入示例。
在Perl的壳牌(PSH) “结合了Unix外壳的互动性用Perl的力量”。可以用 shell 语法输入简单的命令(甚至是管道);其他一切都是 Perl。该项目已经很长时间没有开发了。它是可用的,但还没有达到我考虑在纯 Perl(用于脚本)或纯 shell(用于交互或用于脚本)上使用它的地步。
IPython是一种改进的交互式 Python 控制台,特别针对数值和并行计算。这是一个相对年轻的项目。
irb(交互式 ruby)是 Python 控制台的 Ruby 等价物。
scsh是一种方案实现(即一种体面的编程语言),具有传统上在 unix shell(字符串、进程、文件)中发现的系统绑定类型。然而,它的目标并不是用作交互式 shell。
zsh是一个改进的交互式 shell。它的强项是交互性(命令行版本、完成、使用简洁但神秘的语法完成的常见任务)。它的编程功能不是很好(与 ksh 相当),但它带有许多用于终端控制、正则表达式、网络等的库。
fish是 unix 风格的 shell 的一个干净的开始。它没有更好的编程或系统访问功能。因为它破坏了与 sh 的兼容性,所以它有更多的空间来发展更好的功能,但这并没有发生。
附录:unix 工具箱的另一部分将许多东西视为文件:
/sys提供更多的硬件和系统控制。/proc文件系统完成。也许 unix shell 的未来不是通过命令更好的系统访问(以及更好的控制结构来组合命令),而是通过文件系统更好的系统访问(它们的组合有些不同——我认为我们还没有弄清楚关键习语是什么(比如壳管)是)。
phi*_*urn 14
您不需要太多的 bash 代码来在 bash 中实现类或对象。
说,100 行。
Bash 具有关联数组,可用于实现具有继承、方法和属性的简单对象系统。
因此,您可能会像这样定义一个类:
class Queue N=10 add=q_add remove=q_remove
Run Code Online (Sandbox Code Playgroud)
创建这个队列的一个实例可能是这样完成的:
class Q:Queue N=100
Run Code Online (Sandbox Code Playgroud)
或者
inst Q:Queue N=100
Run Code Online (Sandbox Code Playgroud)
因为类是用数组实现的,所以class和inst实际上是同义词 - 有点像在 javascript 中。
可以像这样将项目添加到此队列中:
$Q add 1 2 aaa bbb "a string"
Run Code Online (Sandbox Code Playgroud)
将项目移入变量 X 可能会像这样完成:
$Q remove X
Run Code Online (Sandbox Code Playgroud)
对象的转储结构可以这样完成:
$Q dump
Run Code Online (Sandbox Code Playgroud)
这将返回如下内容:
Q {
parent=Queue {
parent=ROOT {
this=ROOT
0=dispatch ROOT
}
class=Queue
N=10
add=q_add
remove=q_remove
0=dispatch Queue
}
class=Q
N=4
add=q_add
remove=q_remove
0=dispatch Q
1=
2=ccc ddd
3=
4=
}
Run Code Online (Sandbox Code Playgroud)
类是使用类函数创建的,如下所示:
class(){
local _name="$1:" # append a : to handle case of class with no parent
printf "$FUNCNAME: %s\n" $_name
local _this _parent _p _key _val _members
_this=${_name%%:*} # get class name
_parent=${_name#*:} # get parent class name
_parent=${_parent/:/} # remove handy :
declare -g -A $_this # make class storage
[[ -n $_parent ]] && { # copy parent class members into this class
eval _members=\"\${!$_parent[*]}\" # get indices of members
for _key in $_members; do # inherit members from parent
eval _val=\"\${$_parent[$_key]}\" # get parent value
eval $_this[$_key]=\"$_val\" # set this member
done
}
shift 1
# overwrite with specific values for this object
ROOT_set $_this "$@" "0=dispatch $_this" "parent=${_parent:-ROOT}" "class=$_this"
}
Run Code Online (Sandbox Code Playgroud)
注意:定义新类或实例时,您可以覆盖任何成员值或函数。
Bash 关联数组有一个奇怪的地方,它使这项工作非常顺利:$Q[0]} 与 $Q 相同。这意味着我们可以使用数组名来调用方法调度函数:
dispatch(){
local _this=$1 _method=$2 _fn
shift 2
_fn="$_this[$_method]" # reference to method name
${!_fn} $_this "$@"
}
Run Code Online (Sandbox Code Playgroud)
不利的一面是我不能将 [0] 用于数据,因此我的队列(在这种情况下)从索引 = 1 开始。或者,我可以使用像“q+0”这样的关联索引。
要获取和设置成员,您可以执行以下操作:
# basic set and get for key-value members
ROOT_set(){ # $QOBJ set key=value
local _this=$1 _exp _key _val
shift
for _exp in "$@"; do
_key=${_exp%%=*}
_val="${_exp#*=}"
eval $_this[$_key]=\"$_val\"
done
}
ROOT_get(){ # $QOBJ get var=key
local _this=$1 _exp _var _key
shift
for _exp in "$@"; do
_var=${_exp%%=*}
_key=${_exp#*=}
eval $_var=\"\${$_this[$_key]}\"
done
}
Run Code Online (Sandbox Code Playgroud)
为了转储一个对象结构,我做了这个:
注意:这对于 bash 中的 OOP 不是必需的,但是很高兴看到对象是如何制作的。
# dump any object
obj_dump(){ # obj_dump <object/class name>
local _this=$1 _j _val _key; local -i _tab=${2:-(${#_this}+2)} # add 2 for " {"
_tab+=2 # hanging indent from {
printf "%s {\n" $_this
eval "_key=\"\${!$_this[*]}\""
for _j in $_key; do # print all members
eval "_val=\"\${$_this[\$_j]}\""
case $_j in
# special treatment for parent
parent) printf "%*s%s=" $_tab "" $_j; ${!_val} dump $(( _tab+${#_j}+${#_val}+2 ));;
*) printf "%*s%s=%s\n" $_tab "" $_j "$_val";;
esac
done
(( _tab-=2 ))
printf "%*s}\n" $_tab ""
return 0
}
Run Code Online (Sandbox Code Playgroud)
我的 OOP 设计没有考虑对象中的对象——除了继承的类。你可以单独创建它们,或者创建一个像 class() 这样的特殊构造函数。*obj_dump* 需要修改以检测内部类以递归打印它们。
哦!我手动定义了一个 ROOT 类来简化类功能:
declare -gA ROOT=( \
[this]=ROOT \
[0]="dispatch ROOT" \
[dump]=obj_dump \
[set]="ROOT_set" \
[get]="ROOT_get" \
)
Run Code Online (Sandbox Code Playgroud)
通过一些队列函数,我定义了一些这样的类:
class Queue \
in=0 out=0 N=10 \
dump=obj_dump \
add=q_add \
empty=q_empty \
full=q_full \
peek=q_peek \
remove=q_remove
class RoughQueue:Queue \
N=100 \
shove=q_shove \
head_drop=q_head_drop
Run Code Online (Sandbox Code Playgroud)
创建了一些 Queue 实例并使它们工作:
class Q:Queue N=1000
$Q add aaa bbb "ccc ddd"
$Q peek X
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
class R:RoughQueue N=3
$R shove aa bb cc dd ee ff gg hh ii jj
$R dump
Run Code Online (Sandbox Code Playgroud)
ksh93t+ 在保留 bourne/posix shell 语法的同时引入了一些 OO 概念:http : //blog.fpmurphy.com/2010/05/ksh93-using-types-to-create-object-orientated-scripts.html
| 归档时间: |
|
| 查看次数: |
26556 次 |
| 最近记录: |