Simple Ruby ShellUnix commands and the RSH language
Version 1.0.1
Current source: 1.0.1 | Requires Ruby 4.0 or newer | Unix systems
SRSH 1.0
SRSH is a Unix shell written in Ruby. RSH is the language built into it.
Ordinary commands keep ordinary shell syntax. When a script needs lists, maps, functions,
errors, workers, modules, or objects, it can use RSH without leaving the shell.
SRSH keeps process pipelines and value pipelines separate.
Form
What moves
command | command
Bytes between Unix processes
value |> function
RSH values between functions
$(command)
Command output into an RSH string
cmd("git", "status")
Arguments kept as structured data
What is implemented
Unix pipelines, redirection, connectors, and background jobs
Local and environment bindings
Lists, maps, ranges, strings, numbers, booleans, and void
Functions, lambdas, closures, and value pipelines
Pattern matching and safe access
Prototypes, traits, namespaces, and modules
Structured errors and deferred cleanup
Tasks, atoms, channels, thread pools, and process workers
Parsed code values and reflection
Direct C ABI calls with bridge
Find a manual entry
RSH language manual
This manual describes the 1.0 source tree. Examples use the readable syntax unless the short form is the point.
1. Getting started
Start the interactive shell with srsh, run a script by path, or evaluate a single expression.
srsh
srsh script.rsh one two
srsh -e "[1,2,3] |> sum"
srsh --check script.rsh
srsh -c "printf 'hello\n'"
srsh --norc
At the prompt, assignments, expressions, functions, and blocks are parsed as RSH. Other input is handled as a shell command.
The editor understands multiline blocks, collections, command continuations, and bracketed paste.
2. Shell commands and jobs
These forms run commands through the shell executor:
cat *.log | grep ERROR | sort -u
make -j8 && put built
generate > output.txt 2> errors.txt
long_job &
jobs
fg %1
Implemented operators are |, &&, ||, ;, and background &.
Redirections include <, >, >>, 2>, and 2>>.
The shell supports process groups, jobs, fg, bg, wait %N, aliases, globbing,
tilde expansion, and nested command substitution.
No-match globs stay literal. SRSH is not a Bash parser, so existing Bash scripts should still be run with Bash.
Double quoted strings interpolate full RSH expressions. Single quoted and raw strings do not.
Maps use %[...]. Ranges can include or exclude the upper bound.
Member access uses value.name and indexed access uses value[index]. Safe forms return void when access cannot be completed:
host := cfg?.server?.host ?? "localhost"
first := cfg?.hosts?[0] ?? host
4. Bindings and assignment
name := "Robert"
count := 4
count += 1
name ++= "!"
$EDITOR := "vim"
home := $HOME
first_arg := $1
last_status := $?
:= creates a local in the current lexical scope. Compound assignment updates the nearest existing local.
A leading $ on assignment writes the process environment. Shell commands can expand locals, environment variables,
positional arguments, $?, and $!.
Tasks receive isolated copies of ordinary lists and maps. Shared mutation must use a prototype object, atom, or channel.
5. Operators and value pipelines
Operator groups, from loose to tight, are approximately:
??
or ||
and &&
== != === !== =~ !~ in
< <= > >=
|>
.. ..<
+ - ++
* / %
**
++ concatenates strings. + is numeric unless its operands support a sensible arithmetic addition. Strict equality uses ===.
The value pipeline inserts its left side as the first argument to the call on its right:
fn scale(x, by := 2)
return x * by
end
fn square(x) => x * x
double := ::x => x * 2
sum_rest := ::(head, *tail) => tail |> sum
task fetch(url)
return cmd("curl", "-fsS", url).check().out
end
Functions are first-class values and closures capture lexical values. Parameters may have defaults and one trailing rest parameter.
A task has the same parameter rules, but calling it starts work immediately and returns a task handle.
Short named functions use :: name(args) ... .::. A caret is accepted as the short spelling of return.
7. Control flow
if score >= 90
emit "great"
else
emit "keep going"
end
each users -> user
= user.name
end
while pending
work()
end
Integers are iterable, so each 3 -> i visits 0, 1, and 2. Maps yield key and value pairs. Lists and pairs can be destructured.
The short block markers are ? ... .? for conditions and @ ... .@ for loops. Use break or ^!, and continue or ^>.
The original times N ... end loop and fn name arg ... end function spelling remain available for older scripts.
8. Pattern matching
match status
| 200..299 => = "ok"
| [401, 403] => = "auth"
| ? it >= 500 => = "server"
| _ => = "other"
end
Patterns may be values, ranges, lists, partial maps, prototype references, or guard expressions.
The matched value is available as it in a guard. The short form begins with ?? and ends with .??.
9. Collection functions
The collection toolbox works in call form, pipeline form, and usually method form.
map filter reject fold find any all count sum each sort uniq flat zip enumerate take drop chunk group tap partial compose
total := [1,2,3,4,5,6]
.filter(::x => x % 2 == 0)
.map(::x => x ** 2)
.sum()
by_ext := files |> group(::path => ext(path))
File, path, string, and JSON helpers include:
readfile writefile appendfile exists file dir glob stat mkdirp rmfile cpfile mvfile basename dirname ext json json_dump lines words replace upper lower trim split join shellquote
10. Prototypes, traits, and objects
RSH uses prototypes with composable traits instead of class inheritance.
trait Printable
fn show() => "#{self.name}=#{self.value}"
end
proto Counter(name, start := 0) with Printable
slot name := name
slot value := start
fn inc(by := 1)
self.value += by
return self
end
end
counter := Counter("requests", 10)
counter.inc()
Slot compound updates are synchronized. Reflection helpers include fields(), methods(),
protoof(), is(), and clone().
11. Namespaces and modules
space build
root := "out"
fn artifact(name) => root ++ "/" ++ name
end
use "./lib/net.rsh" as net
= build.artifact("app")
= net.fetch(url)
A space may contain bindings, functions, tasks, prototypes, traits, nested spaces, bridges, and code declarations.
use runs a file inside its own namespace. Relative paths are resolved against the importing script, and import cycles are rejected.
Caught errors provide at least .type and .message. Deferred calls and blocks run last-in, first-out when
the current script or function scope exits, including on return and error. fail() raises an error and assert() checks a condition.
Task methods are await, done, status, and cancel.
race(tasks) cancels losers. await_all(tasks) preserves order and cancels unfinished siblings when one fails.
parallel(values, fn, workers) uses Ruby threads and suits files, networks, and subprocess waits.
pmap(values, fn, workers) uses Unix fork workers for CPU work and preserves input order.
Buffer methods include size, address, ptr, read, write, string, and clear.
16. Code values and reflection
code cleanup
rm build/tmp/cache
end
= sourceof(cleanup)
run(cleanup)
formula := "x * 3"
= eval(formula)
code ... end parses source without running it. Dynamic helpers are eval, code, run,
valid, and sourceof. Introspection functions include locals, fns, protos, and traits.
17. Built-in function reference
Conversion
int float str bool type
Numbers and choice
round floor ceil sqrt clamp abs min max rand pick
Strings
len empty contains starts ends starts_with ends_with split join upper lower trim replace lines words
Maps
keys values fields
Environment
env cwd clock status cpu_count
Processes
capture sh cmd shellquote
Concurrency
spawn await await_all race parallel pmap chan atom sleep
Errors
attempt fail assert
Objects
clone fields methods protoof is
Files
readfile writefile appendfile exists file dir glob stat mkdirp rmfile cpfile mvfile basename dirname ext
Data
json json_dump
Code
eval code run sourceof valid locals fns protos traits
Native
cbuf
18. Shell configuration
Shell strictness is controlled with regular shell commands:
strict enables pipefail and nounset. It does not copy Bash set -e.
~/.srshrc
Startup commands
~/.srsh_history
Interactive history
~/.srsh/themes
Private .theme and .json theme files
~/.srsh/plugins
Private .rsh and trusted .rb plugins
Use scheme --list, scheme NAME, plugins, and reload to manage the interactive environment.
Ruby plugins are trusted code. Plugin and theme files must pass owner and mode checks before automatic loading.
Core shell commands are:
cd pwd put echo printf ls alias unalias set export unset read true false sleep source . exit quit help hist clearhist scheme theme themes plugins reload jobs wait fg bg exec systemfetch which type dirs pushd popd umask kill option
Ruby 4.0 or newer is required. RubyGems installs Fiddle 1.1.8 or newer for native bridges. Building the optional native extension also needs a C compiler and Ruby development headers.
gem install ./srsh.gem
srsh --version
srsh
Run from the source archive
The shell can run as Ruby-only code. The native helper is optional when running from a checkout or source archive.
tar -xzf srsh-source.tar.gz
cd srsh-1.0.1
make test
./bin/srsh
Install from a checkout
git clone https://github.com/RobertFlexx/RSH.git
cd RSH
make test
make PREFIX="$HOME/.local" install
The direct branch snapshot is also available as a zip file.
Verify a download
sha256sum -c SHA256SUMS
The checksum file covers the stable and versioned artifacts attached to the release.
RSH examples
These examples correspond to programs in the repository and use features present in the 1.0 tree.
bin/srsh command entry point
lib/srsh/ shell and language implementation
lib/srsh/language/ RSH lexer, parser, values, evaluator
lib/srsh/shell/ command lexer, executor, jobs, terminal
ext/srsh_native/ optional C helper
examples/ sample RSH programs
language-docs/ long-form language and security notes
docs/ this static site
test/ language and shell tests
Release policy
A tag such as v1.0.1 must match Srsh::VERSION. The release workflow runs syntax checks,
the test suite, example validation, smoke tests, and the native build. It then creates gem and source artifacts,
writes SHA-256 checksums, and creates the GitHub release at that tag.
Scope
SRSH is a shell and a language implementation under active development. It is not a secure sandbox and it is not
a drop-in Bash interpreter. Ruby plugins and C bridges are trusted, process-level extension points.