bashrs 0.4.0

Rust-to-Shell transpiler for deterministic bootstrap scripts
Documentation

Rash - Rust to Shell Transpiler

Crates.io Documentation License CI Coverage Tests PropertyTests

Rash transpiles a safe subset of Rust to POSIX-compliant shell scripts, enabling you to write maintainable and type-safe shell scripts using familiar Rust syntax.

Why Rash?

  • ๐Ÿ›ก๏ธ Safety First: Automatic protection against shell injection attacks
  • ๐Ÿ” Compile-Time Verification: Catch errors before deployment
  • ๐Ÿ“ฆ Zero Runtime Dependencies: Generated scripts work on any POSIX shell
  • ๐ŸŽฏ Deterministic Output: Same input always produces identical scripts
  • โœ… ShellCheck Compliant: All output passes strict linting

Quick Start

Write Rust:

// install.rs
#[rash::main]
fn main() {
    let version = env_var_or("VERSION", "1.0.0");
    let prefix = env_var_or("PREFIX", "/usr/local");
    
    echo("Installing MyApp {version} to {prefix}");
    
    // Create installation directories
    mkdir_p("{prefix}/bin");
    mkdir_p("{prefix}/share/myapp");
    
    // Copy files (with automatic quoting)
    if exec("cp myapp {prefix}/bin/") {
        echo("โœ“ Binary installed");
    } else {
        echo("โœ— Failed to install binary");
        exit(1);
    }
}

Get POSIX shell:

$ bashrs build install.rs -o install.sh
$ cat install.sh
#!/bin/sh
# Generated by Rash v0.4.0
# POSIX-compliant shell script

set -euf
IFS=' 	
'
export LC_ALL=C

# Rash runtime functions
rash_require() {
    if ! "$@"; then
        echo "FATAL: Requirement failed: $*" >&2
        exit 1
    fi
}

# Main script begins
main() {
    VERSION="${VERSION:-1.0.0}"
    PREFIX="${PREFIX:-/usr/local}"
    
    echo "Installing MyApp $VERSION to $PREFIX"
    
    mkdir -p "$PREFIX/bin"
    mkdir -p "$PREFIX/share/myapp"
    
    if cp myapp "$PREFIX/bin/"; then
        echo "โœ“ Binary installed"
    else
        echo "โœ— Failed to install binary"
        exit 1
    fi
}

# Execute main function
main "$@"

Installation

From crates.io (Recommended)

cargo install bashrs

Binary Releases

Pre-built binaries are available for Linux and macOS:

# Linux x86_64
curl -L https://github.com/paiml/bashrs/releases/latest/download/bashrs-x86_64-unknown-linux-musl.tar.gz | tar xz

# macOS x86_64
curl -L https://github.com/paiml/bashrs/releases/latest/download/bashrs-x86_64-apple-darwin.tar.gz | tar xz

# macOS ARM64
curl -L https://github.com/paiml/bashrs/releases/latest/download/bashrs-aarch64-apple-darwin.tar.gz | tar xz

Using cargo-binstall

cargo binstall bashrs

From Source

# Full build with all features
cargo install --git https://github.com/paiml/bashrs

# Minimal build (smaller binary, ~2MB)
cargo install --git https://github.com/paiml/bashrs --no-default-features --features minimal

Usage

Basic Commands

# Transpile a Rust file to shell
bashrs build input.rs -o output.sh

# Check if a file is valid Rash
bashrs check input.rs

# Verify safety properties
bashrs verify input.rs --verify strict

# Start interactive playground (if built with playground feature)
bashrs playground

CLI Options

USAGE:
    bashrs [OPTIONS] <COMMAND>

COMMANDS:
    build       Transpile Rust to shell script
    check       Validate Rust source without transpiling
    verify      Run formal verification
    inspect     Analyze AST and safety properties
    playground  Interactive development environment (requires feature)

OPTIONS:
    -v, --verbose    Enable verbose output
    -V, --version    Print version information
    -h, --help       Print help information

BUILD OPTIONS:
    -o, --output <FILE>      Output file (default: stdout)
    -O, --optimize <LEVEL>   Optimization level: none, size, readability (default: readability)
    -t, --target <SHELL>     Target shell: posix, bash, ash (default: posix)
    --verify <LEVEL>         Verification level: none, basic, strict, paranoid

Language Features

Supported Rust Subset

Rash supports a carefully chosen subset of Rust that maps cleanly to shell:

Variables and Types

let name = "Alice";              // String literals
let count = 42;                  // Integers (including negatives: -42)
let flag = true;                 // Booleans
let user = env("USER");          // Environment variables
let result = capture("date");    // Command output

Arithmetic Operations

let x = 1 + 2;                   // Addition โ†’ $((1 + 2))
let y = 10 - 3;                  // Subtraction โ†’ $((10 - 3))
let z = 4 * 5;                   // Multiplication โ†’ $((4 * 5))
let w = 20 / 4;                  // Division โ†’ $((20 / 4))

Comparison Operators

if x > 0 {                       // Greater than โ†’ [ "$x" -gt 0 ]
    println!("Positive");        // println! macro supported
}
if y == 5 { ... }                // Equal โ†’ [ "$y" -eq 5 ]
if z < 10 { ... }                // Less than โ†’ [ "$z" -lt 10 ]

User-Defined Functions

fn add(a: i32, b: i32) -> i32 {
    a + b                        // Return value via echo
}

fn main() {
    let sum = add(1, 2);         // Captured with $(add 1 2)
    println!("Sum: {}", sum);
}

Built-in Functions

// I/O operations
echo("Hello, World!");           // Print to stdout
println!("Hello, World!");       // println! macro (Sprint 10)
eprint("Error!");                // Print to stderr

// File system
mkdir_p("/tmp/myapp");           // Create directory recursively
write_file("config.txt", data);  // Write file
let content = read_file("config.txt");  // Read file
if path_exists("/etc/config") { ... }   // Check path

// Process management  
exec("ls -la");                  // Run command
let output = capture("date");    // Capture command output
exit(0);                         // Exit with code

// Environment
set_env("KEY", "value");         // Set environment variable
let val = env("KEY");            // Get environment variable
let val = env_var_or("KEY", "default"); // With default

Control Flow

// Conditionals
if condition {
    // ...
} else if other {
    // ...
} else {
    // ...
}

// โš ๏ธ Pattern matching - Not yet supported (P2 backlog)
// match value {
//     "linux" => echo("Linux detected"),
//     "darwin" => echo("macOS detected"),
//     _ => echo("Unknown OS"),
// }

Loops

// โš ๏ธ For loops - Not yet supported (P2 backlog)
// for i in 0..10 {
//     echo("Iteration: {i}");
// }

// โš ๏ธ While loops - Not yet supported
// let mut count = 0;
// while count < 10 {
//     count = count + 1;
// }

Safety Features

All generated scripts are protected against:

  • Command Injection: All variables are properly quoted
  • Path Traversal: Paths are validated and escaped
  • Glob Expansion: Glob patterns are quoted when needed
  • Word Splitting: IFS is set to safe value
  • Undefined Variables: set -u catches undefined vars

Example of automatic safety:

let user_input = env("UNTRUSTED");
exec("echo {user_input}");  // Safe: becomes echo "$user_input"

Examples

See the examples/ directory for complete examples:

Shell Compatibility

Generated scripts are tested on:

Shell Version Status
POSIX sh - โœ… Full support
dash 0.5.11+ โœ… Full support
bash 3.2+ โœ… Full support
ash (BusyBox) 1.30+ โœ… Full support
zsh 5.0+ โœ… Full support
mksh R59+ โœ… Full support

Performance

Rash is designed for fast transpilation:

  • 21.1ยตs transpile time for simple scripts (100x better than target!)
  • Memory usage <10MB for most scripts
  • Generated scripts add minimal overhead (~20 lines boilerplate)

Quality Metrics (v0.4.0)

Metric Status
Tests 520/520 โœ…
Property Tests 23 (~13,300 cases) โœ…
Coverage 85.36% โœ…
Complexity <10 cognitive โœ…
Performance 21ยตs โœ…
ShellCheck 24/24 pass โœ…
Edge Cases Fixed 7/11 (64%) ๐ŸŸก

Production Ready: All P0 (critical) and P1 (high priority) edge cases resolved.

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Clone the repository
git clone https://github.com/paiml/rash.git
cd rash

# Run tests
make test

# Run with all checks
make validate

# Build release binary
make release

License

Rash is licensed under the MIT License. See LICENSE for details.

Acknowledgments

Rash is built with safety principles inspired by:

  • ShellCheck for shell script analysis
  • Oil Shell for shell language design
  • The Rust community for memory safety practices

Roadmap

Completed (v0.4.0):

  • Core transpilation engine
  • Basic safety validation
  • ShellCheck compliance (24/24 tests)
  • Property-based testing (23 properties, ~13,300 cases)
  • Arithmetic expressions ($((expr)))
  • Function return values
  • Negative integers
  • Integer comparisons
  • println! macro
  • Global function scope
  • MCP server (rash-mcp)

In Progress:

  • For loops (P2 - parser work required)
  • Match expressions (P2 - pattern matching)

Future:

  • Language server (LSP)
  • Incremental compilation
  • More shell targets (fish, PowerShell)
  • Package manager integration

See ROADMAP.md for detailed sprint planning.