#shell #docker #declarative #bindings #bash #task #ansible

bin+lib rash_core

Declarative shell scripting using Rust native bindings

49 stable releases

Uses new Rust 2024

new 2.9.7 Mar 27, 2025
2.9.1 Feb 9, 2025
2.9.0 Nov 11, 2024
1.10.5 Jul 4, 2024
0.1.0 May 17, 2020

#51 in Development tools

Download history 15/week @ 2024-12-04 57/week @ 2024-12-11 106/week @ 2025-02-05 33/week @ 2025-02-12 3/week @ 2025-02-26 50/week @ 2025-03-12 473/week @ 2025-03-19

526 downloads per month
Used in mdbook_rash

Custom license and maybe LGPL-3.0

340KB
9K SLoC

rash

Build status Documentation crates.io concept-map Rash license Rash Aur package

Rash is a lightweight, container-friendly shell scripting language that uses a declarative YAML syntax inspired by Ansible. It brings the simplicity and readability of Ansible playbooks to local scripting and container entrypoints, all in a single Rust binary with no dependencies.

Why Rash?

  • Declarative vs Imperative: Define what your script should accomplish, not how
  • Container-Optimized: Single binary with no dependencies, perfect for minimal containers
  • Lightweight: Runs on any Linux system, even resource-constrained IoT devices
  • Template-Powered: Uses MiniJinja for powerful templating capabilities
  • Intuitive Syntax: Familiar YAML structure for those who know Ansible
  • Built-in Command-Line Parsing: Elegant docopt implementation for clean script interfaces
  • Modular Design: Focused modules for different tasks

Example: Imperative vs Declarative

Bash (Imperative)

#!/bin/bash
set -e

# Validate required environment variables
REQUIRED_PARAMS="
DATABASE_URL
DATABASE_USER
DATABASE_PASSWORD
LOG_LEVEL
"

for required in $REQUIRED_PARAMS ; do
  [[ -z "${!required}" ]] && echo "$required IS NOT DEFINED" && exit 1
done

# Configure the application
echo "[$0] Configuring application..."
CONFIG_FILE="/app/config.json"
cat > $CONFIG_FILE << EOF
{
  "database": {
    "url": "$DATABASE_URL",
    "user": "$DATABASE_USER",
    "password": "$DATABASE_PASSWORD"
  },
  "server": {
    "port": "${SERVER_PORT:-8080}",
    "log_level": "$LOG_LEVEL"
  }
}
EOF

# Set correct permissions
chmod 0600 $CONFIG_FILE

echo "[$0] Starting application..."
exec "$@"

Rash (Declarative)

#!/usr/bin/env rash

- name: Verify input parameters
  assert:
    that:
      - env.DATABASE_URL is defined
      - env.DATABASE_USER is defined
      - env.DATABASE_PASSWORD is defined
      - env.LOG_LEVEL is defined

- name: Configure application
  template:
    src: config.j2
    dest: /app/config.json
    mode: "0600"
  vars:
    server_port: "{{ env.SERVER_PORT | default('8080') }}"

- name: Launch command
  command:
    cmd: "{{ rash.argv }}"
    transfer_pid: yes

Installation

Binary (Linux/macOS)

curl -s https://api.github.com/repos/rash-sh/rash/releases/latest \
    | grep browser_download_url \
    | grep $(uname -m) \
    | grep $(uname | tr '[:upper:]' '[:lower:]') \
    | grep -v musl \
    | cut -d '"' -f 4 \
    | xargs curl -s -L \
    | sudo tar xvz -C /usr/local/bin

Arch Linux (AUR)

yay -S rash

Cargo

cargo install rash_core

Docker

docker run --rm -v /usr/local/bin/:/output --entrypoint /bin/cp ghcr.io/rash-sh/rash:latest /bin/rash /output/

Key Features

Built-in Command-Line Interface Parser

#!/usr/bin/env -S rash --
#
# Copy files from source to dest dir
#
# Usage:
#   copy.rh [options] <source>... <dest>
#   copy.rh
#
# Options:
#   -h --help    show this help message and exit
#   --mode MODE  dest file permissions [default: 0644]

- copy:
    src: "{{ item }}"
    dest: "{{ dest }}/{{ item | split('/') | last }}"
    mode: "{{ options.mode }}"
  loop: "{{ source | default([]) }}"

Container Entrypoints

Perfect for creating maintainable container entrypoints that handle environment validation, configuration management, and service initialization:

FROM alpine:3.16

# Install rash binary
ADD https://github.com/rash-sh/rash/releases/download/v0.6.0/rash-x86_64-unknown-linux-musl.tar.gz /tmp/
RUN tar xvzf /tmp/rash-x86_64-unknown-linux-musl.tar.gz -C /usr/local/bin && \
    rm /tmp/rash-x86_64-unknown-linux-musl.tar.gz

# Add entrypoint script
COPY entrypoint.rh /entrypoint.rh
RUN chmod +x /entrypoint.rh

ENTRYPOINT ["/entrypoint.rh"]

Templating System

Access environment variables and use powerful filters:

- name: Configure application
  template:
    src: config.j2
    dest: /etc/app/config.json
  vars:
    app_port: "{{ env.PORT | default('8080') }}"
    app_log_level: "{{ env.LOG_LEVEL | default('info') }}"
    database_url: "{{ env.DATABASE_URL }}"

Privilege Escalation

Run commands as different users with the built-in become functionality:

- name: Configure system DNS
  become: true
  copy:
    dest: /etc/resolv.conf
    content: |
      nameserver 208.67.222.222
      nameserver 208.67.220.220

Documentation

For comprehensive documentation, visit: https://rash-sh.github.io/docs/rash/master/

Community

License

Rash is distributed under the GPL-3.0 License.

Dependencies

~17–46MB
~769K SLoC