Rubish: A Unix shell written in pure Ruby Rubish is a UNIX shell written in pure Ruby that parses shell syntax and compiles it to Ruby code for execution by the Ruby VM. It is fully compatible with bash, allowing existing bash scripts to run without modification, while deeply integrating Ruby so users can seamlessly mix shell commands with Ruby code, blocks, iterators, and libraries. The shell also supports Ruby method call syntax for commands, Ruby iterator blocks for processing output, direct evaluation of Ruby code from the prompt, and Ruby-style function definitions with named parameters. A UNIX shell written in pure Ruby. Shell syntax is parsed and compiled to Ruby code, then executed by the Ruby VM. Rubish supports all the features of bash, and the shell syntax is fully compatible. You can run your existing bash scripts without modification. If you found any bash script that doesn't work in rubish, we consider it a bug, so please report it Rubish is not just a shell implemented in Ruby, but a shell that deeply integrates Ruby. You can seamlessly mix shell commands and Ruby code, and even use Ruby's powerful features like blocks, iterators, and libraries in your shell scripts. 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 is a small bash launcher that finds a usable Ruby on its own probes ~/.rbenv/shims/ruby , /opt/homebrew/bin/ruby , /usr/local/bin/ruby , system Ruby; honors $RUBY . Use it when bundler isn't around — for example as a login shell, from a .app bundle, or anywhere PATH may be minimal: ./bin/rubish RUBY=/opt/homebrew/opt/ruby@3.4/bin/ruby ./bin/rubish explicit override Start an interactive shell: rubish Run a single command: rubish -c 'echo hello' Run a script: rubish script.sh Or you can even use this as a login shell echo "$ which rubish " | sudo tee -a /etc/shells chsh -s "$ which rubish " Use Ruby expressions as conditions in if , while , and until by wrapping them in { } . Shell variables are automatically bound as local variables in the Ruby expression: 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 Commands can be invoked using Ruby method call syntax with parentheses, in addition to the traditional UNIX style with spaces: These are equivalent: ls -la ls '-la' Arguments can be passed as method arguments: cat file.txt grep 'pattern', file.txt Commands can be chained with Ruby methods using dot notation, forming a pipeline. The chain has to be opened by a parenthesized call, an array literal, or a block — once you're in chain context, subsequent methods can be bare: Equivalent to ls | sort ls .sort Equivalent to ls | sort | uniq ls .sort.uniq Equivalent to cat file.txt | grep error cat file.txt .grep /error/ Chains can be combined with blocks see "Ruby iterator blocks" below ls.select { it.end with? '.rb' }.each { |f| puts f.upcase } The first segment needs the parens because bare cmd.method is ambiguous with paths and dotted filenames ./script.sh , file.tar.gz — once confirms a method-call form, the lexer knows it's safe to chain. Ruby iterator methods .each , .map , .select , .detect can take blocks to process command output line by line: ls.each { |f| puts f.upcase } cat file.txt .map { |line| line.strip } ls.select { it.end with? '.rb' } Any line starting with a capital letter is evaluated as Ruby code directly. This means you can use Ruby classes, methods, and expressions right from the shell prompt without any special syntax: js rubish$ Time.now = 2025-01-01 12:00:00 +0900 rubish$ Dir.glob ' .rb' .sort = "Gemfile", "Rakefile" rubish$ ENV 'HOME' = "/Users/you" Multi-line blocks work too — rubish detects unfinished Ruby open do , missing end , unterminated strings, etc. and prompts for continuation lines, both at the interactive prompt and inside sourced rcfiles. Only single-line interactive expressions get the IRB-style = … value printed; multi-line blocks and sourced statements run silently for their side effects. Ruby array literals can be used directly in shell context. Rubish distinguishes them from glob patterns like a-z automatically: js rubish$ 1, 2, 3 .map { |x| x x } = 1, 4, 9 You can execute any Ruby code by surrounding it with a lambda expression - { } : php rubish$ - { 2 10 } = 1024 In addition to the standard shell function syntax, rubish supports Ruby-style def...end with named parameters and splat args: python def greet name echo "Hello, $name" end def log level, messages echo " $level $messages" end greet world = Hello, world Define your prompt as a Ruby function for full programmatic control. The function is called on every prompt render, so it can include dynamic content: 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 You can also use the traditional PS1 / RPROMPT variables with bash \X or zsh %X escape codes. Rubish tab-completes most commands out of the box, with no per-tool setup files to install. The completer derives subcommands and flags from each tool's own --help output, on demand: bash rubish$ git