
2026/05/23 15:32
Rubish:純粋な Ruby で書かれた Unix シェル
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Rubish は、Ruby で実装された純粋な UNIX シェルであり、完全な Bash 互換性を備えており、既存の Bash スクリプトをそのまま実行できることを保証します(あらゆる逸脱はバグとして扱われます)。開発者がプロンプト内でブロック、イテレータ、ライブラリ、クラスを通じてシステムコマンドと高レベルの Ruby ロジックを直接組み合わせられるようにすることで、Ruby 統合を深めます。コマンドの実行には Ruby 風のシンタックスが採用されており、条件式は
{ } 内において Ruby 式表現を用い(例:{ if ... })、メソッドは括弧または引数で呼び出せる(例:ls('-la'))、パイプラインは自然に連鎖する(例:ls().sort.uniq())、そしてコマンド出力はイテレータ(例:.each, .map, .select, .detect)を使用して行ごとに処理されます。大文字で始まる行はインライン Ruby 評価をトリガーし、Time.now や Dir.glob('*.rb').sort のような機能をサポートします。Rubish はまた、Ruby 風の関数定義(def...end)、カスタムプロンプト、遅いバックグラウンド初期化、および非信用可能なスクリプト用の制限モード(rubish -r)をサポートします。Zsh 互換性もほぼ完全であり、setopt/unsetopt、compdef/compinit、fpath を通じたオートロード、そして %X プロンプトコードを処理します。公開 API(require 'rubish')により Ruby アプリケーションがプロセス内でシェルセッションを駆動でき、フォークと exec のオーバーヘッドなしでシンタックスハイライト、補完、パースを実現します。Rubish は Homebrew(brew tap amatsuda/rubish && brew install --HEAD rubish)から即座にインストールでき、ソースからも入手可能です。また、最小経路の Ruby 検出のための Bash ランチャーを含み、インタラクティブモードをサポートし、/etc/shells と chsh を通じてシステム全体ログインシェルとして設定できます。本文
Rubish: 純粋な Ruby による UNIX シェル実装
Ruby VM によって実行され、シェル構文を Ruby コードへコンパイルする、UNIX シェルとしての純粋な Rubyによる実装です。
コンセプト
- Bash と完全互換: Rubish は Bash の全ての機能をサポートし、既存の Bash スクリプトをそのまま動作させます。動作しないスクリプトはバグですのでご報告ください。
- 深い Ruby 統合: シェルコマンドと Ruby コードをシームレスに混在させられ、ブロックやライブラリなど Ruby の強力な機能を活用できます。
インストール
Homebrew (macOS)
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 を探索する小さなランチャーです。Bundler が利用できない環境(.app バンドル内や最小限の PATH など)でも使用できます:
./bin/rubish RUBY=/opt/homebrew/opt/ruby@3.4/bin/ruby ./bin/rubish # 明示的な上書き
使用方法
- インタラクティブなシェル:
rubish - シングルコマンド:
rubish -c 'ls -la' - スクリプト実行:
rubish script.sh - ログインシェルとして設定:
echo "$(which rubish)" | sudo tee -a /etc/shells && chsh -s "$(which rubish)"
Bash 以上の機能
Ruby の条件式
if、while、until の条件句を { } で囲むことで Ruby 式を使用可能です。
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
Ruby スタイルのメソッド呼び出し
括弧を使用した Ruby 式構文でコマンドを起動できます。
とls -la
は同等です。ls('-la')
やcat(file.txt)
のように引数を渡せます。grep('pattern', file.txt)
メソッドチェーン
Ruby のドット演算子を使用して、コマンドチェーンとパイプラインを形成できます。
# ls | sort.uniq と同等 ls().sort.uniq # cat file.txt | grep(/error/) と同等 cat(file.txt).grep(/error/) # ブロックとの組み合わせ ls.select { it.end_with?('.rb') }.each { |f| puts f.upcase }
※ 最初の命令に括弧
() を付けることで、ファイル名と区別するためです。
Ruby イテレーターブロック
.each、.map、.select など、Ruby のイテレーターを出力処理に使用できます。
ls.each { |f| puts f.upcase }cat(file.txt).map { |line| line.strip }
インライン Ruby 評価
大文字で始まる行は、直接 Ruby コードとして評価されます。
rubish$ Time.now => 2025-01-01 12:00:00 +0900 rubish$ Dir.glob('*.rb').sort => ["Gemfile", "Rakefile"]
Ruby アレイと正規表現
Ruby アレイリテラルや globs パターンがシェルコンテキストで直接使えます。
=>rubish$ [1, 2, 3].map { |x| x * x }[1, 4, 9]
Lambda と関数定義
Lambda 表現
-> { } や Ruby スタイルの def...end をサポートします。
rubish$ -> { 2 ** 10 } => 1024 def greet(name) echo "Hello, $name" end greet world # => Hello, world
カスタム Ruby プロンプト
rubish_prompt および rubish_right_prompt を Ruby 関数として定義し、動的コンテンツや Git 情報を表示できます。
def rubish_prompt branch = `git branch --show-current 2>/dev/null`.strip dir = Dir.pwd.sub(ENV['HOME'], '~') "\e[36m#{dir}\e[0m \e[33m#{branch}\e[0m $ " end def rubish_right_prompt Time.now.strftime('%H:%M:%S') end
遅延読み込み (lazy_load
)
lazy_load環境変数の初期化や
rbenv init などの重い処理を、次のプロンプト直前まで背景スレッドで延期できます。
# ~/.rubishrc 内 lazy_load { `rbenv init - --no-rehash bash` } lazy_load { `nodenv init - bash` }
制限モード (-r
)
-r不信任なスクリプト実行時に、Ruby 統合機能(インライン評価、ラムダなど)を全無効化します。標準的なシェル構文のみが利用可能です:
rubish -r script.sh
Zsh 互換性
/setoptunsetopt
/compdef
、compinit
(fpath)autoload
プロンプトコード%X- 簡略化されたパス展開 (
)a/c<Tab>
設定ファイル
順に読み込まれる構成ファイルです。
- ログインシェル:
/etc/profile
または~/.config/rubish/profile~/.rubish_profile
- インタラクティブシェル:
または~/.config/rubish/config~/.rubishrc
(プロジェクトローカル)./.rubishrc
- ログアウト:
または~/.config/rubish/logout~/.rubish_logout
Ruby プログラムへの埋め込み
公開 API を提供し、ターミナルエミュレーターや GUI から Rubish セッションを直接制御できます(Echoes ターミナルなどで利用中)。
require 'rubish' repl = Rubish::REPL.new(login_shell: true) # インタラクティブ実行 repl.run # プログラマティックな操作 repl.tokenize('ls | grep foo') repl.try_parse('if true; then') repl.parse_ast('echo hi') repl.complete_at(line: 'gi', point: 2)
Subprocess Hook
fork()/exec() の間に子プロセスで実行されるフックを設定できます。
Rubish::Command.child_pre_exec_hook = -> { Process.setsid # ...ioctls, シグナルハンドラなど... }
ビルトインコマンド一覧
| カテゴリ | コマンド |
|---|---|
| ディレクトリ | cd, pwd, pushd, popd, dirs |
| I/O | echo, printf, read, mapfile, readarray |
| 変数 | export, declare, typeset, readonly, unset, local, shift, set |
| プロセス | exit, logout, exec, kill, wait, times |
| ジョブ制御 | jobs, fg, bg, disown, suspend |
| 関数 | function, return, caller |
| Alias | alias, unalias |
| 履歴 | history, fc |
| 実行 | eval, source, ., command, builtin |
| テスト | test, [, [[, (( )), let |
| 制御 | break, continue, trap |
| 補完 | complete, compgen, compopt, bind |
| 設定 | shopt, setopt, unsetopt |
| 情報 | help, type, which, hash |
| その他 | true, false, :, getopts, umask, ulimit, enable |
開発
bundle install bundle exec rake test
コントリビューション
バグ報告とプルリクエストは GitHub をご検討ください。 https://github.com/amatsuda/rubish
ライセンス
MIT