rush: the shell
rush ("RUst SHell") is a POSIX-style shell written in Rust with minimal dependencies, so that it ports to an operating system that is not Unix. It is the console shell and the SSH login shell of Motor OS, and it also builds and runs on Linux.
Conformance is measured rather than asserted: a corpus of POSIX snippets is run
through both rush and dash, and the two must agree on stdout and exit
status. The deliberate differences are listed in the test file, and each is itself
tested, so a difference cannot be quietly introduced or quietly fixed.
Interactive use
- Line editing with arrows, Home and End, and the usual emacs keys (^A ^E ^B ^F ^K ^U ^W ^Y ^T ^L ^D, M-b, M-f, M-d, word-wise Ctrl and Alt arrows); UTF-8 edited by character, including double-width characters; lines that wrap across rows. The editor repaints only what changed, so a slow serial console does not flicker.
- Tab completion of commands (builtins, functions, aliases,
$PATH), file names, and$variables, quoting-aware in both directions. - History: Up and Down, reverse search with ^R, the
historybuiltin, and persistence through$HISTFILEand$HISTSIZE; a multi-line command is one history entry. - ^C abandons the line and ^D ends the session with
$?. - The prompt is the colored
rush:$PWD$by default;PS1,PS2, andPS4are ordinary expanded variables. An interactive shell sources$ENV; a login shell also reads/etc/profileand~/.profile. On Motor OS, sys-tty setsENV=/system/cfg/rush.cfg.
The language
- External commands and multi-stage pipelines, including builtins, compound
commands, and functions as pipeline stages (
cmd | while read x; do ...; done). ;,&&,||, pipeline!, and\line continuation.if/elif/else,for,while/until,casewith|alternation and glob patterns, brace groups, subshells, and functions withreturn,break n, andcontinue n.- Variables,
$?,$#,$@,$*, positional parameters,export, and inlineVAR=value command. - Word expansion:
${var:-default}and the other:=,:?,:+,${#x},#,##,%,%%forms; command substitution with$(...)and backticks; arithmetic$((...)); tilde; field splitting onIFS; pathname globbing. - Redirections
<,>,>>,2>,2>&1,<>, and here-documents, on simple commands, compound commands, and builtins. Which redirections hand a child a real file and which use a pipe is described under Terminals. traponEXITand on signal names or numbers, even though Motor OS has no signals: ^C at the prompt raisesINTbecause rush detects the byte itself, and a foreground child that exits 130 is treated as interrupted.- Background jobs with
cmd &,$!,wait,jobs, andfg;killwith-s,-NAME,-N,%job,-l, and-0. On Motor OS,killcan only terminate. - Shell options, enforced:
set -e(with the POSIX condition-context rules),-u,-xviaPS4,-n,-f,-Cwith>|,-a,-v,-o pipefail, and$-. - POSIX invocation:
rush [options] script [args...],-c string,-s, clustered and+-form options,--.
Builtins
Special: : . eval exec exit export readonly set shift unset times trap break
continue return. Regular: cd pwd echo printf test [ read true false getopts
command type hash alias unalias umask wait jobs fg bg kill. Extensions:
history, clear, and quit.
Deliberate differences from dash
set -o pipefail exists (POSIX.1-2024 added it). -h is accepted
as an inert option. $- lists options in a fixed order. set -v
echoes a script in one piece, since rush reads a whole script before parsing it. The
default prompt is colored (PS1='$ ' restores dash's). history,
clear, and quit are builtins; clear is one the Motor OS
image needs because it ships no external clear. Aliases expand at execution
rather than parse time, so alias e=echo; e hi works in a single
-c string.
Motor OS specifics
A System-role console shell explicitly grants CAP_SYS to the commands it
runs, because the default spawn rule never propagates System; an Interactive shell's
commands inherit Interactive by the default rule. A per-command
MOTOR_OS_CAPS=... command assignment replaces that grant and can narrow the
child. Programs on rush's detached-spawn list, such as rmux, are started with
CAP_SPAWN_DETACHED so that they can leave a server running after the session
ends. Background jobs are started without the terminal input stream, since Motor has no
SIGTTIN to stop them from stealing keystrokes, and for the same reason there is
no interactive job control (^Z, bg): a foreground command runs until
it exits or is interrupted. rush re-exports
$COLUMNS and $LINES before every command so that a full-screen
program starts at the right size, and it sets the rmux window title to the foreground
command's name.