Shell脚本和Ruby代码终于不用互相嫌弃了。
有个叫Rubish的新项目,用纯Ruby写了一个Unix Shell。它的思路很直接:把Shell语法解析编译成Ruby代码,然后交给Ruby虚拟机执行。开发者说,Rubish完整支持bash的所有功能,语法层面完全兼容——你现有的bash脚本不用改一行就能跑。如果发现有跑不通的,他们当bug处理。
![]()
但这不只是"用Ruby重写了bash"那么简单。Rubish的设计核心是让Shell命令和Ruby代码能无缝混着写。你可以在脚本里直接调用Ruby的块、迭代器和各种库,反过来也能在Ruby表达式里用Shell变量。
![]()
装起来不麻烦。Mac用户可以用brew:
brew tap amatsuda/rubish
brew install --HEAD rubish
或者从源码跑:
git clone https://github.com/amatsuda/rubish.git
cd rubish
bundle install
bundle exec exe/rubish
项目还提供了一个bin/rubish的小启动器,能自己找可用的Ruby环境——它会按顺序探测~/.rbenv/shims/ruby、/opt/homebrew/bin/ruby、/usr/local/bin/ruby和系统Ruby,也认$RUBY环境变量。适合当登录Shell用,或者从.app bundle里启动,那种PATH极简的场景。
用起来和常规Shell差不多。交互模式直接敲rubish,单条命令用rubish -c 'echo hello',跑脚本就rubish script.sh。想设成默认登录Shell也行,按标准流程加到/etc/shells然后chsh就行。
真正有意思的是语法层面。条件判断可以用Ruby表达式,包在花括号里,Shell变量会自动绑定成局部变量:
COUNT=5
if { count.to_i > 3 }
echo 'count is greater than 3'
end
循环也一样:
while { count.to_i > 0 }
echo $COUNT
COUNT=$((COUNT - 1))
done
![]()
命令调用有两种风格。传统的Unix空格分隔照样用,ls -la没问题。同时支持Ruby的方法调用语法,ls('-la')等价。参数按位置传,cat(file.txt)、grep('pattern', file.txt)都行。
管道被重新设计成了方法链。ls().sort就是ls | sort,ls().sort.uniq对应三层管道。关键是链的开头必须用括号调用、数组字面量或者块来"激活"——一旦进入链式上下文,后面的方法可以裸写。这么设计是因为bare cmd.method有歧义,可能是路径或带点号的文件名,括号能消除歧义。
所以cat(file.txt).grep(/error/)等价于cat file.txt | grep error,而且这里grep的参数是Ruby正则。更复杂的例子:
ls.select { it.end_with?('.rb') }.each { |f| puts f.upcase }
这行里select和each都是Ruby迭代器,it是Ruby 3.4引入的隐式块参数。整条链从Shell命令开始,中间用Ruby方法处理,最后Ruby输出。
迭代器方法.each、.map、.select、.detect都能接块,逐行处理命令输出:
ls.each { |f| puts f.upcase }
cat(file.txt).map { |line| line.strip }
ls.select { it.end_with?('.rb') }
还有条特殊规则:任何以大写字母开头的行,直接当Ruby代码执行。这意味着类定义、方法调用、随便什么Ruby表达式,都能直接写在脚本里。
对写惯了Ruby的人来说,这套设计省掉了很多上下文切换的成本。不用在"Shell思维"和"Ruby思维"之间来回切,一套语法管到底。对运维脚本、自动化流程这种Shell和Ruby本来就会混用的场景,或许能减少一些胶水代码。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.