penguin/utils

my env utils

commit 8f56dec6f0d22f357dd745c9e229b5e6a98e6d25

author斟酌 鵬兄 <tgckpg@gmail.com>
date2026-06-26T10:17:41Z
subjectRestructure rbashrc
commit 8f56dec6f0d22f357dd745c9e229b5e6a98e6d25
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2026-06-26T10:17:41Z

    Restructure rbashrc
---
 bash/core/00_env.bash                              |  12 +
 bash/core/05_config.bash                           |  18 +
 bash/core/10_shell.bash                            |  39 ++
 bash/core/20_io.bash                               |  58 +++
 bash/core/30_loader.bash                           |  65 +++
 bash/core/40_sources.bash                          | 103 ++++
 bash/core/50_upgrade.bash                          |  35 ++
 bash/core/90_prompt.bash                           |  13 +
 bash/defaults.conf                                 |   4 +
 bash/rbashrc                                       | 563 ++++++++++++---------
 bash/rbashrc.in                                    |  27 +
 bash/sources/{20_fast-greps => 14_shortcuts_greps} |   0
 bash/sources/30_mysql                              |  82 ---
 bash/tools/build-rbashrc.sh                        |  27 +
 14 files changed, 718 insertions(+), 328 deletions(-)

diff --git a/bash/core/00_env.bash b/bash/core/00_env.bash
new file mode 100755
index 0000000..817ba70
--- /dev/null
+++ b/bash/core/00_env.bash
@@ -0,0 +1,12 @@
+# Host prompt placeholders can be replaced by rbash-upgrade/install.
+RHOSTNAME="${RHOSTNAME:-<HOSTNAME>}"
+RDOMAIN="${RDOMAIN:-<DOMAIN>}"
+RCOLOR="${RCOLOR:-<RCOLOR>}"
+
+if [ "$RHOSTNAME" = "<HOSTNAME>" ]; then
+  RHOSTNAME="\u"
+  RDOMAIN="@$(hostname -s)"
+  RCOLOR=$(( RANDOM * 6 / 32767 + 1 ))
+fi
+
+_RBASH_LOADED=
\ No newline at end of file
diff --git a/bash/core/05_config.bash b/bash/core/05_config.bash
new file mode 100755
index 0000000..71eea9a
--- /dev/null
+++ b/bash/core/05_config.bash
@@ -0,0 +1,18 @@
+rbash_init_config() {
+  if [ -f "$RBASH_CONFIG" ]; then
+    return 0
+  fi
+
+  rbash_download "$RBASH_REMOTE/$RBASH_REPO/raw/$RBASH_REF/$RBASH_PATH/defaults.conf" \
+    > "$RBASH_CONFIG" || {
+      cat > "$RBASH_CONFIG" <<'EOF'
+rbash_load "sources/10_aliases"
+rbash_load "sources/12_shortcuts"
+rbash_load "sources/20_fast-greps"
+rbash_load "sources/40_go-command"
+rbash_load "sources/41_pivot-command"
+EOF
+    }
+
+  chmod 600 "$RBASH_CONFIG"
+}
\ No newline at end of file
diff --git a/bash/core/10_shell.bash b/bash/core/10_shell.bash
new file mode 100755
index 0000000..38ab4ff
--- /dev/null
+++ b/bash/core/10_shell.bash
@@ -0,0 +1,39 @@
+# Source global definitions.
+if [ -f /etc/bashrc ]; then
+  # shellcheck source=/etc/bashrc
+  source /etc/bashrc
+fi
+
+HISTCONTROL=ignoreboth
+HISTSIZE=1000
+HISTFILESIZE=2000
+
+shopt -s histappend
+shopt -s checkwinsize
+
+if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
+  debian_chroot="$(cat /etc/debian_chroot)"
+fi
+
+if [ -f "$HOME/.bash_aliases" ]; then
+  # shellcheck source=/dev/null
+  source "$HOME/.bash_aliases"
+fi
+
+if ! shopt -oq posix; then
+  if [ -f /usr/share/bash-completion/bash_completion ]; then
+    # shellcheck source=/usr/share/bash-completion/bash_completion
+    source /usr/share/bash-completion/bash_completion
+  elif [ -f /etc/bash_completion ]; then
+    # shellcheck source=/etc/bash_completion
+    source /etc/bash_completion
+  fi
+fi
+
+__func_head() {
+  echo "Usage: ${FUNCNAME[1]} $*"
+}
+
+__func_help() {
+  echo "       ${FUNCNAME[1]} $*"
+}
\ No newline at end of file
diff --git a/bash/core/20_io.bash b/bash/core/20_io.bash
new file mode 100755
index 0000000..6f19dc7
--- /dev/null
+++ b/bash/core/20_io.bash
@@ -0,0 +1,58 @@
+rbash_url() {
+  local path="$1"
+  printf '%s/%s/raw/%s/%s/%s\n' \
+    "$RBASH_REMOTE" "$RBASH_REPO" "$RBASH_REF" "$RBASH_PATH" "$path"
+}
+
+rbash_download() {
+  local url="$1"
+
+  if command -v curl >/dev/null 2>&1; then
+    curl -fsSL "$url" || {
+      local rc=$?
+      echo "rbash: download failed: $url" >&2
+      echo "rbash: curl exit code: $rc" >&2
+      return "$rc"
+    }
+  elif command -v wget >/dev/null 2>&1; then
+    wget -qO- "$url" || {
+      local rc=$?
+      echo "rbash: download failed: $url" >&2
+      echo "rbash: wget exit code: $rc" >&2
+      return "$rc"
+    }
+  else
+    echo "rbash: curl or wget is required" >&2
+    return 127
+  fi
+}
+
+rbash_cache() {
+  local url="$1"
+  local key file
+
+  if command -v md5sum >/dev/null 2>&1; then
+    key="$(printf '%s' "$url" | md5sum | cut -d' ' -f1)"
+  else
+    key="$(printf '%s' "$url" | md5 | cut -d' ' -f1)"
+  fi
+
+  file="$RBASH_CACHE_DIR/$key"
+
+  if [ ! -f "$file" ]; then
+    rbash_download "$url" > "$file" || {
+      rm -f "$file"
+      return 1
+    }
+    chmod 700 "$file"
+  fi
+
+  printf '%s\n' "$file"
+}
+
+_require_jq() {
+  if ! command -v jq >/dev/null 2>&1; then
+    echo "This command requires jq." >&2
+    return 1
+  fi
+}
diff --git a/bash/core/30_loader.bash b/bash/core/30_loader.bash
new file mode 100755
index 0000000..47ab551
--- /dev/null
+++ b/bash/core/30_loader.bash
@@ -0,0 +1,65 @@
+rbash_load() {
+  local rel="$1"
+  local url file
+
+  if [ -z "${_RBASH_MERGE_START:-}" ]; then
+    if [ -n "$_RBASH_LOADED" ]; then
+      return 0
+    fi
+
+    if [ -f "$RBASH_MERGED" ]; then
+      # shellcheck source=/dev/null
+      source "$RBASH_MERGED" && {
+        _RBASH_LOADED=1
+        return 0
+      }
+
+      rm -f "$RBASH_MERGED"
+    fi
+  fi
+
+  echo "Load: $rel"
+
+  url="$(rbash_url "$rel")"
+  file="$(rbash_cache "$url")" || {
+    echo "    ..download failed" >&2
+    return 1
+  }
+
+  # shellcheck source=/dev/null
+  if source "$file"; then
+    {
+      printf 'echo "Load: %s"\n' "$rel"
+      cat "$file"
+      printf '\n'
+    } >> "$RBASH_MERGED"
+  else
+    echo "    ..failed" >&2
+    printf 'echo "Skipped: %s. Use rbash-reload to try again."\n' "$rel" >> "$RBASH_MERGED"
+  fi
+
+  chmod 700 "$RBASH_MERGED"
+}
+
+rbash-reload() {
+  _RBASH_LOADED=
+  _RBASH_MERGE_START=1
+  rm -f "$RBASH_MERGED"
+
+  # shellcheck source=/dev/null
+  source "$RBASH_CONFIG"
+
+  _RBASH_MERGE_START=
+}
+
+rbash-run() {
+  local rel="$1"
+  local file
+
+  shift || true
+
+  echo "Getting: $rel"
+
+  file="$(rbash_cache "$(rbash_url "$rel")")" || return 1
+  "$file" "$@"
+}
\ No newline at end of file
diff --git a/bash/core/40_sources.bash b/bash/core/40_sources.bash
new file mode 100755
index 0000000..8ce1c21
--- /dev/null
+++ b/bash/core/40_sources.bash
@@ -0,0 +1,103 @@
+rbash_sources_json_url() {
+  printf '%s/%s/tree/%s/tree.json\n' \
+    "$RBASH_REMOTE" "$RBASH_REPO" "$RBASH_REF"
+}
+
+declare -gA _RBASH_DICT
+
+rbash-list() {
+  _require_jq || return 1
+
+  local item key enabled_marker
+  echo "Available sources:"
+
+  while IFS= read -r item; do
+    key="$(printf '%s' "$item" | grep -o '^[0-9]\+' || true)"
+    [ -n "$key" ] && _RBASH_DICT["s$key"]="$item"
+
+    enabled_marker=" "
+    if grep -q -F "rbash_load \"sources/$item\"" "$RBASH_CONFIG"; then
+      enabled_marker="*"
+    fi
+
+    printf '  %s %s\n' "$enabled_marker" "$item"
+  done < <(
+    rbash_download "$(rbash_sources_json_url)" |
+      jq -r '
+        .[]
+        | select(.path == "bash/sources" or (.path | startswith("bash/sources/")))
+        | .path
+        | sub("^bash/sources/?"; "")
+        | select(length > 0)
+      '
+  )
+}
+
+r2ensource() {
+  rbash-list || return 1
+
+  local ids id selected tmp
+  local -a enable=()
+
+  read -r -p "Enter the script id XX, delimited by space: " ids
+
+  for id in $ids; do
+    selected="${_RBASH_DICT["s$id"]}"
+
+    if [ -z "$selected" ]; then
+      echo "No such id: $id" >&2
+      return 1
+    fi
+
+    if grep -q -F "rbash_load \"sources/$selected\"" "$RBASH_CONFIG"; then
+      echo "$selected is already enabled."
+      continue
+    fi
+
+    enable+=("$selected")
+  done
+
+  tmp="$(mktemp)"
+  cp "$RBASH_CONFIG" "$tmp"
+
+  for selected in "${enable[@]}"; do
+    echo "rbash_load \"sources/$selected\"" >> "$tmp"
+    echo "Enabling $selected"
+  done
+
+  sort -u "$tmp" > "$RBASH_CONFIG"
+  rm -f "$tmp"
+  rm -rf "$RBASH_CACHE_DIR"
+}
+
+r2dissource() {
+  local ids id tmp pattern
+
+  echo "Currently enabled sources:"
+  grep -E '^rbash_load "sources/' "$RBASH_CONFIG" |
+    sed 's/^rbash_load "sources\///; s/"$//' |
+    sed 's/^/    /'
+
+  read -r -p "Enter the script id XX, delimited by space: " ids
+
+  tmp="$(mktemp)"
+  cp "$RBASH_CONFIG" "$tmp"
+
+  for id in $ids; do
+    pattern="rbash_load \"sources/${id}_"
+
+    if ! grep -q -F "$pattern" "$tmp"; then
+      echo "No such id: $id" >&2
+      rm -f "$tmp"
+      return 1
+    fi
+
+    echo "Disabling $id"
+    grep -v -F "$pattern" "$tmp" > "$tmp.next"
+    mv "$tmp.next" "$tmp"
+  done
+
+  sort -u "$tmp" > "$RBASH_CONFIG"
+  rm -f "$tmp"
+  rm -rf "$RBASH_CACHE_DIR"
+}
\ No newline at end of file
diff --git a/bash/core/50_upgrade.bash b/bash/core/50_upgrade.bash
new file mode 100755
index 0000000..c81bb34
--- /dev/null
+++ b/bash/core/50_upgrade.bash
@@ -0,0 +1,35 @@
+rbash-upgrade() {
+  echo "Updating $__RBASH_SCRIPT"
+
+  local tmp new_host new_domain new_color
+  tmp="$(mktemp)"
+
+  rbash_download "$(rbash_url "rbashrc")" > "$tmp" || {
+    rm -f "$tmp"
+    return 1
+  }
+
+  if [ -n "${1:-}" ]; then
+    new_host="$1"
+    new_domain="${2:-}"
+    new_color="${3:-$RCOLOR}"
+  else
+    new_host="$RHOSTNAME"
+    new_domain="$RDOMAIN"
+    new_color="$RCOLOR"
+  fi
+
+  sed \
+    -e "s|<HOSTNAME>|$new_host|g" \
+    -e "s|<DOMAIN>|$new_domain|g" \
+    -e "s|<RCOLOR>|$new_color|g" \
+    "$tmp" > "$tmp.new"
+
+  mv "$tmp.new" "$__RBASH_SCRIPT"
+  rm -f "$tmp"
+
+  rm -rf "$RBASH_CACHE_DIR"
+
+  # shellcheck source=/dev/null
+  source "$__RBASH_SCRIPT"
+}
\ No newline at end of file
diff --git a/bash/core/90_prompt.bash b/bash/core/90_prompt.bash
new file mode 100755
index 0000000..cf103a6
--- /dev/null
+++ b/bash/core/90_prompt.bash
@@ -0,0 +1,13 @@
+_SHELLD="\$"
+
+case "$OSTYPE" in
+  cygwin*)
+    if net session >/dev/null 2>&1; then
+      _SHELLD="#"
+    fi
+    ;;
+esac
+
+export PS1="This is ${RHOSTNAME}\e[1;3${RCOLOR}m${RDOMAIN}\e[0m: \w\n$_SHELLD "
+export EDITOR="${EDITOR:-vim}"
+export PATH="$RBASH_BIN:$PATH"
\ No newline at end of file
diff --git a/bash/defaults.conf b/bash/defaults.conf
new file mode 100644
index 0000000..a2060ed
--- /dev/null
+++ b/bash/defaults.conf
@@ -0,0 +1,4 @@
+rbash_load "sources/10_aliases"
+rbash_load "sources/12_shortcuts"
+rbash_load "sources/40_go-command"
+rbash_load "sources/41_pivot-command"
diff --git a/bash/rbashrc b/bash/rbashrc
old mode 100644
new mode 100755
index 55b94be..0b7e0a6
--- a/bash/rbashrc
+++ b/bash/rbashrc
@@ -1,19 +1,24 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
+# Generated from bash/rbashrc.in + bash/core/*.
+# Do not edit bash/rbashrc directly.
 
-# If not running interactively, don't do anything
 case $- in
-    *i*) ;;
-      *) return;;
+  *i*) ;;
+  *) return ;;
 esac
 
-__SCRIPT=$BASH_SOURCE
-RBASH_HOME="$HOME/.rbash"
+__RBASH_SCRIPT="${BASH_SOURCE[0]}"
+
+RBASH_HOME="${RBASH_HOME:-$HOME/.rbash}"
+RBASH_REMOTE="${RBASH_REMOTE:-https://sgit.k8s.astropenguin.net}"
+RBASH_REPO="${RBASH_REPO:-penguin/utils}"
+RBASH_REF="${RBASH_REF:-master}"
+RBASH_PATH="${RBASH_PATH:-bash}"
+
 RBASH_SOURCES="$RBASH_HOME/sources"
 RBASH_CONFIG="$RBASH_HOME/config"
 RBASH_ENV="$RBASH_HOME/env"
-RBASH_REMOTE="https://sgit.k8s.astropenguin.net"
-RBASH_REPO="penguin/utils"
-RBASH_PATH="bash"
 RBASH_MERGED="$RBASH_SOURCES/merged"
 RBASH_BIN="$RBASH_HOME/bin"
 
@@ -21,304 +26,370 @@ RHOSTNAME="<HOSTNAME>"
 RDOMAIN="<DOMAIN>"
 RCOLOR="<RCOLOR>"
 
-if [ "$RHOSTNAME" == "<HOSTNAME"">" ]; then
-	RHOSTNAME="\u"
-	RDOMAIN="@"$( hostname -s )
-	RCOLOR=$(( $RANDOM * 6 / 32767 + 1 ))
+# ---- rbash: bash/core/00_env.bash ----
+
+# Host prompt placeholders can be replaced by rbash-upgrade/install.
+RHOSTNAME="${RHOSTNAME:-<HOSTNAME>}"
+RDOMAIN="${RDOMAIN:-<DOMAIN>}"
+RCOLOR="${RCOLOR:-<RCOLOR>}"
+
+if [ "$RHOSTNAME" = "<HOSTNAME>" ]; then
+  RHOSTNAME="\u"
+  RDOMAIN="@$(hostname -s)"
+  RCOLOR=$(( RANDOM * 6 / 32767 + 1 ))
 fi
 
-# Source global definitions
+_RBASH_LOADED=
+
+# ---- rbash: bash/core/05_config.bash ----
+
+rbash_init_config() {
+  if [ -f "$RBASH_CONFIG" ]; then
+    return 0
+  fi
+
+  rbash_download "$RBASH_REMOTE/$RBASH_REPO/raw/$RBASH_REF/$RBASH_PATH/defaults.conf" \
+    > "$RBASH_CONFIG" || {
+      cat > "$RBASH_CONFIG" <<'EOF'
+rbash_load "sources/10_aliases"
+rbash_load "sources/12_shortcuts"
+rbash_load "sources/20_fast-greps"
+rbash_load "sources/40_go-command"
+rbash_load "sources/41_pivot-command"
+EOF
+    }
+
+  chmod 600 "$RBASH_CONFIG"
+}
+
+# ---- rbash: bash/core/10_shell.bash ----
+
+# Source global definitions.
 if [ -f /etc/bashrc ]; then
-    . /etc/bashrc
+  # shellcheck source=/etc/bashrc
+  source /etc/bashrc
 fi
 
-# don't put duplicate lines or lines starting with space in the history.
-# See bash(1) for more options
 HISTCONTROL=ignoreboth
-
-# append to the history file, don't overwrite it
-shopt -s histappend
-
-# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
 HISTSIZE=1000
 HISTFILESIZE=2000
 
-# check the window size after each command and, if necessary,
-# update the values of LINES and COLUMNS.
+shopt -s histappend
 shopt -s checkwinsize
 
-# If set, the pattern "**" used in a pathname expansion context will
-# match all files and zero or more directories and subdirectories.
-#shopt -s globstar
-
-# make less more friendly for non-text input files, see lesspipe(1)
-#[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
-
-# set variable identifying the chroot you work in (used in the prompt below)
 if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
-    debian_chroot=$(cat /etc/debian_chroot)
+  debian_chroot="$(cat /etc/debian_chroot)"
 fi
 
-# set a fancy prompt (non-color, unless we know we "want" color)
-case "$TERM" in
-    xterm-color) color_prompt=yes;;
-esac
-
-# Alias definitions.
-# You may want to put all your additions into a separate file like
-# ~/.bash_aliases, instead of adding them here directly.
-# See /usr/share/doc/bash-doc/examples in the bash-doc package.
-
-if [ -f ~/.bash_aliases ]; then
-    . ~/.bash_aliases
+if [ -f "$HOME/.bash_aliases" ]; then
+  # shellcheck source=/dev/null
+  source "$HOME/.bash_aliases"
 fi
 
-# enable programmable completion features (you don't need to enable
-# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
-# sources /etc/bash.bashrc).
 if ! shopt -oq posix; then
   if [ -f /usr/share/bash-completion/bash_completion ]; then
-    . /usr/share/bash-completion/bash_completion
+    # shellcheck source=/usr/share/bash-completion/bash_completion
+    source /usr/share/bash-completion/bash_completion
   elif [ -f /etc/bash_completion ]; then
-    . /etc/bash_completion
+    # shellcheck source=/etc/bash_completion
+    source /etc/bash_completion
   fi
 fi
 
-function __func_head() { echo "Usage:" ${FUNCNAME[1]} $1; }
-function __func_help() { echo "       ${FUNCNAME[1]} $1"; }
+__func_head() {
+  echo "Usage: ${FUNCNAME[1]} $*"
+}
 
-function __download {
-    which curl 2>&1 > /dev/null
-    if [ $? -eq 0 ]; then
-        curl -s "$1"
-        return $?
-    fi
+__func_help() {
+  echo "       ${FUNCNAME[1]} $*"
+}
 
-    which wget 2>&1 > /dev/null
-    if [ $? -eq 0 ]; then
-        wget -qO- "$1"
-        return $?
-    fi
+# ---- rbash: bash/core/20_io.bash ----
+
+rbash_url() {
+  local path="$1"
+  printf '%s/%s/raw/%s/%s/%s\n' \
+    "$RBASH_REMOTE" "$RBASH_REPO" "$RBASH_REF" "$RBASH_PATH" "$path"
+}
+
+rbash_download() {
+  local url="$1"
+
+  if command -v curl >/dev/null 2>&1; then
+    curl -fsSL "$url" || {
+      local rc=$?
+      echo "rbash: download failed: $url" >&2
+      echo "rbash: curl exit code: $rc" >&2
+      return "$rc"
+    }
+  elif command -v wget >/dev/null 2>&1; then
+    wget -qO- "$url" || {
+      local rc=$?
+      echo "rbash: download failed: $url" >&2
+      echo "rbash: wget exit code: $rc" >&2
+      return "$rc"
+    }
+  else
+    echo "rbash: curl or wget is required" >&2
+    return 127
+  fi
+}
+
+rbash_cache() {
+  local url="$1"
+  local key file
+
+  if command -v md5sum >/dev/null 2>&1; then
+    key="$(printf '%s' "$url" | md5sum | cut -d' ' -f1)"
+  else
+    key="$(printf '%s' "$url" | md5 | cut -d' ' -f1)"
+  fi
+
+  file="$RBASH_CACHE_DIR/$key"
+
+  if [ ! -f "$file" ]; then
+    rbash_download "$url" > "$file" || {
+      rm -f "$file"
+      return 1
+    }
+    chmod 700 "$file"
+  fi
+
+  printf '%s\n' "$file"
+}
+
+_require_jq() {
+  if ! command -v jq >/dev/null 2>&1; then
+    echo "This command requires jq." >&2
+    return 1
+  fi
 }
 
-function rbash_cache {
-    local CACHE_FILE
-    MLINK=$( echo "$1" | md5sum | cut -d' ' -f1 )
 
-    CACHE_FILE="$RBASH_SOURCES/$MLINK"
+# ---- rbash: bash/core/30_loader.bash ----
+
+rbash_load() {
+  local rel="$1"
+  local url file
+
+  if [ -z "${_RBASH_MERGE_START:-}" ]; then
+    if [ -n "$_RBASH_LOADED" ]; then
+      return 0
+    fi
+
+    if [ -f "$RBASH_MERGED" ]; then
+      # shellcheck source=/dev/null
+      source "$RBASH_MERGED" && {
+        _RBASH_LOADED=1
+        return 0
+      }
 
-    if [ ! -f "$CACHE_FILE" ]; then
-        __download "$1" > "$CACHE_FILE"
+      rm -f "$RBASH_MERGED"
     fi
+  fi
 
-    chmod 700 "$CACHE_FILE"
-    echo -n "$CACHE_FILE"
+  echo "Load: $rel"
+
+  url="$(rbash_url "$rel")"
+  file="$(rbash_cache "$url")" || {
+    echo "    ..download failed" >&2
+    return 1
+  }
+
+  # shellcheck source=/dev/null
+  if source "$file"; then
+    {
+      printf 'echo "Load: %s"\n' "$rel"
+      cat "$file"
+      printf '\n'
+    } >> "$RBASH_MERGED"
+  else
+    echo "    ..failed" >&2
+    printf 'echo "Skipped: %s. Use rbash-reload to try again."\n' "$rel" >> "$RBASH_MERGED"
+  fi
+
+  chmod 700 "$RBASH_MERGED"
 }
 
-_RBASH_LOADED=
-mkdir -p "$RBASH_SOURCES" "$RBASH_BIN"
+rbash-reload() {
+  _RBASH_LOADED=
+  _RBASH_MERGE_START=1
+  rm -f "$RBASH_MERGED"
 
-if [ ! -f "$RBASH_SOURCES/merged" ]; then
-	_RBASH_MERGE_START=1
-fi
+  # shellcheck source=/dev/null
+  source "$RBASH_CONFIG"
 
-function rbash_load {
-    local f path
-
-	if [ -z "$_RBASH_MERGE_START" ]; then
-		if [ -n "$_RBASH_LOADED" ]; then
-			return 0
-		fi
-
-		if [ -f "$RBASH_MERGED" ]; then
-			source $RBASH_MERGED
-			if [ $? -eq 0 ]; then
-				_RBASH_LOADED=1
-				return 0
-			fi
-			rm "$RBASH_MERGED"
-		fi
-	fi
-
-    echo "Load: $1"
-    f=`rbash_cache "$RBASH_REMOTE/$RBASH_REPO/raw/master/$RBASH_PATH/$1"`
-    source "$f"
-	if [ $? -eq 0 ]; then
-		echo "echo \"Load: $1\"" >> "$RBASH_MERGED"
-		cat "$f" >> "$RBASH_SOURCES/merged"
-	else
-		echo "    ..failed"
-		echo "echo \"Skipped: $1\". Use rbash-reload to try load this again." >> "$RBASH_MERGED"
-	fi
-
-	chmod 700 "$RBASH_MERGED"
+  _RBASH_MERGE_START=
 }
 
-function rbash-reload {
-	_RBASH_LOADED=
-	_RBASH_MERGE_START=1
-	rm -f "$RBASH_SOURCES/merged"
-	source "$RBASH_CONFIG"
-	_RBASH_MERGE_START=
+rbash-run() {
+  local rel="$1"
+  local file
+
+  shift || true
+
+  echo "Getting: $rel"
+
+  file="$(rbash_cache "$(rbash_url "$rel")")" || return 1
+  "$file" "$@"
+}
+
+# ---- rbash: bash/core/40_sources.bash ----
+
+rbash_sources_json_url() {
+  printf '%s/%s/tree/%s/tree.json\n' \
+    "$RBASH_REMOTE" "$RBASH_REPO" "$RBASH_REF"
 }
 
-function rbash-upgrade {
-    echo "Updating $__SCRIPT"
+declare -gA _RBASH_DICT
 
-    local TMPFILE _P_HOSTNAME _P_DOMAIN _P_COLOR
+rbash-list() {
+  _require_jq || return 1
 
-    TMPFILE=$( mktemp )
-    __download "$RBASH_REMOTE/$RBASH_REPO/raw/master/$RBASH_PATH/rbashrc" > $TMPFILE
+  local item key enabled_marker
+  echo "Available sources:"
 
-    if [ -n "$1" ]; then
-        RHOSTNAME=$1
-        RDOMAIN=$2
+  while IFS= read -r item; do
+    key="$(printf '%s' "$item" | grep -o '^[0-9]\+' || true)"
+    [ -n "$key" ] && _RBASH_DICT["s$key"]="$item"
+
+    enabled_marker=" "
+    if grep -q -F "rbash_load \"sources/$item\"" "$RBASH_CONFIG"; then
+      enabled_marker="*"
     fi
 
-    _P_HOSTNAME="<HOSTNAME"">"
-    _P_DOMAIN="<DOMAIN"">"
-    _P_COLOR_CODE="<RCOLOR"">"
+    printf '  %s %s\n' "$enabled_marker" "$item"
+  done < <(
+    rbash_download "$(rbash_sources_json_url)" |
+      jq -r '
+        .[]
+        | select(.path == "bash/sources" or (.path | startswith("bash/sources/")))
+        | .path
+        | sub("^bash/sources/?"; "")
+        | select(length > 0)
+      '
+  )
+}
+
+r2ensource() {
+  rbash-list || return 1
 
-    sed -i \
-        -e "s/$_P_HOSTNAME/$RHOSTNAME/g" \
-        -e "s/$_P_DOMAIN/$RDOMAIN/g" \
-        -e "s/$_P_COLOR_CODE/$RCOLOR/g" \
-         $TMPFILE
+  local ids id selected tmp
+  local -a enable=()
 
-    mv $TMPFILE $__SCRIPT
+  read -r -p "Enter the script id XX, delimited by space: " ids
 
-    # Clean up the old dir
-    if [ $? -eq 0 ] && [ -d "$RBASH_SOURCES" ]; then
-        rm -r "$RBASH_SOURCES"
+  for id in $ids; do
+    selected="${_RBASH_DICT["s$id"]}"
+
+    if [ -z "$selected" ]; then
+      echo "No such id: $id" >&2
+      return 1
     fi
 
-    source $__SCRIPT
-}
+    if grep -q -F "rbash_load \"sources/$selected\"" "$RBASH_CONFIG"; then
+      echo "$selected is already enabled."
+      continue
+    fi
 
-function rbash-run {
-    local f
-    echo "Getting: $1"
+    enable+=("$selected")
+  done
 
-    f=`rbash_cache "$RBASH_REMOTE/$RBASH_REPO/raw/branch/master/$1"`
-    shift
+  tmp="$(mktemp)"
+  cp "$RBASH_CONFIG" "$tmp"
 
-    "$f" "$@"
+  for selected in "${enable[@]}"; do
+    echo "rbash_load \"sources/$selected\"" >> "$tmp"
+    echo "Enabling $selected"
+  done
+
+  sort -u "$tmp" > "$RBASH_CONFIG"
+  rm -f "$tmp"
+  rm -rf "$RBASH_CACHE_DIR"
 }
 
-function _require_jq {
-    which jq 2>&1 > /dev/null
-    if [ $? -ne 0 ]; then
-        echo This command requires jq.
-        return 1
+r2dissource() {
+  local ids id tmp pattern
+
+  echo "Currently enabled sources:"
+  grep -E '^rbash_load "sources/' "$RBASH_CONFIG" |
+    sed 's/^rbash_load "sources\///; s/"$//' |
+    sed 's/^/    /'
+
+  read -r -p "Enter the script id XX, delimited by space: " ids
+
+  tmp="$(mktemp)"
+  cp "$RBASH_CONFIG" "$tmp"
+
+  for id in $ids; do
+    pattern="rbash_load \"sources/${id}_"
+
+    if ! grep -q -F "$pattern" "$tmp"; then
+      echo "No such id: $id" >&2
+      rm -f "$tmp"
+      return 1
     fi
-}
 
-declare -A _RBASH_DICT
-function rbash-list {
-    _require_jq || return 1
-
-    echo "Available sources:"
-	local _k
-    for i in `__download "$RBASH_REMOTE/$RBASH_REPO/tree/master/tree.json" | jq -r '.[] | select(.path | startswith("bash/sources")) | .path | sub("^bash/sources/?"; "")'`; do
-		_k=`echo -n $i | grep -o "^[0-9]\+"`
-		_RBASH_DICT["s$_k"]=$i
-        grep -q -e "^rbash_load \"sources/$i\"\$" "$RBASH_CONFIG"
-        if [ $? -eq 0 ]; then
-            echo "  * $i"
-        else
-            echo "    $i"
-        fi
-    done
-}
+    echo "Disabling $id"
+    grep -v -F "$pattern" "$tmp" > "$tmp.next"
+    mv "$tmp.next" "$tmp"
+  done
 
-function r2ensource {
-	rbash-list || return 1
-
-	local _id _sel _tmp _en
-	_en=()
-	read -p "Enter the script id XX, delimited by space: " _ids
-	for _id in $_ids; do
-		_sel=${_RBASH_DICT["s$_id"]}
-		if [ -z "$_sel" ]; then
-			echo "No such id $_id"
-			return 1
-		fi
-
-		grep -q -e "^rbash_load \"sources/$_sel\"\$" "$RBASH_CONFIG"
-		if [ $? -eq 0 ]; then
-			echo "\"$_sel\" is already enabled."
-			continue
-		fi
-
-		_en+=("$_sel")
-	done
-
-	_tmp=$( mktemp )
-	cp "$RBASH_CONFIG" "$_tmp"
-	for _id in "${_en[@]}"; do
-		echo "rbash_load \"sources/$_id\"" >> $_tmp
-		echo "Enabling $_id"
-	done
-	sort $_tmp > "$RBASH_CONFIG"
-	rm -r "$_tmp" "$RBASH_SOURCES"
+  sort -u "$tmp" > "$RBASH_CONFIG"
+  rm -f "$tmp"
+  rm -rf "$RBASH_CACHE_DIR"
 }
 
-function r2dissource {
-	echo "Currently enabled sources:"
-	grep -e "^rbash_load \"sources/" "$RBASH_CONFIG" | cut -c 21- | tr -d '"' | sed "s/^/    $1/g"
-
-	local _id _dis _opts
-	_dis=()
-	read -p "Enter the script id XX, delimited by space: " _ids
-	for _id in $_ids; do
-		_dis+=("$( grep -e "^rbash_load \"sources/${_id}_" "$RBASH_CONFIG" )")
-		if [ $? -ne 0 ]; then
-			echo "No such id: $_id"
-			return 1
-		fi
-	done
-
-	_opts=""
-	for _id in "${_dis[@]}"; do
-		_opts="-e \"^$( echo -n $_id | sed 's/"/\\"/g' )$\" $_opts"
-		echo "Disabling "$( echo -n $_id | sed 's/rbash_load \"sources\/\([^"]\+\)"/\1/g' )
-	done
-
-	_dis=$( mktemp )
-	sh -c "grep -v $_opts \"$RBASH_CONFIG\"" > $_dis
-	sort $_dis > $RBASH_CONFIG
-	rm -r "$_dis" "$RBASH_SOURCES"
+# ---- rbash: bash/core/50_upgrade.bash ----
+
+rbash-upgrade() {
+  echo "Updating $__RBASH_SCRIPT"
+
+  local tmp new_host new_domain new_color
+  tmp="$(mktemp)"
+
+  rbash_download "$(rbash_url "rbashrc")" > "$tmp" || {
+    rm -f "$tmp"
+    return 1
+  }
+
+  if [ -n "${1:-}" ]; then
+    new_host="$1"
+    new_domain="${2:-}"
+    new_color="${3:-$RCOLOR}"
+  else
+    new_host="$RHOSTNAME"
+    new_domain="$RDOMAIN"
+    new_color="$RCOLOR"
+  fi
+
+  sed \
+    -e "s|<HOSTNAME>|$new_host|g" \
+    -e "s|<DOMAIN>|$new_domain|g" \
+    -e "s|<RCOLOR>|$new_color|g" \
+    "$tmp" > "$tmp.new"
+
+  mv "$tmp.new" "$__RBASH_SCRIPT"
+  rm -f "$tmp"
+
+  rm -rf "$RBASH_CACHE_DIR"
+
+  # shellcheck source=/dev/null
+  source "$__RBASH_SCRIPT"
 }
 
+# ---- rbash: bash/core/90_prompt.bash ----
+
 _SHELLD="\$"
-case $OSTYPE in
-	cygwin)
-		net session > /dev/null 2>&1
-		if [ $? -eq 0 ]; then
-			_SHELLD="#"
-		fi
-		;;
+
+case "$OSTYPE" in
+  cygwin*)
+    if net session >/dev/null 2>&1; then
+      _SHELLD="#"
+    fi
+    ;;
 esac
 
 export PS1="This is ${RHOSTNAME}\e[1;3${RCOLOR}m${RDOMAIN}\e[0m: \w\n$_SHELLD "
-export EDITOR=vim
-export PATH="$RBASH_BIN:$PATH"
-
-# Source for custom bash env, allows overriding
-if [ -f "$RBASH_ENV" ]; then
-    source "$RBASH_ENV"
-fi
-
-# Create default source config
-if [ ! -f "$RBASH_CONFIG" ]; then
-    cat <<___DEFAULT___ > "$RBASH_CONFIG"
-rbash_load "sources/10_aliases"
-rbash_load "sources/12_shortcuts"
-rbash_load "sources/20_fast-greps"
-rbash_load "sources/40_go-command"
-rbash_load "sources/41_pivot-command"
-___DEFAULT___
-    chmod 600 "$RBASH_CONFIG"
-fi
-
-source "$RBASH_CONFIG"
+export EDITOR="${EDITOR:-vim}"
+export PATH="$RBASH_BIN:$PATH"
\ No newline at end of file
diff --git a/bash/rbashrc.in b/bash/rbashrc.in
new file mode 100644
index 0000000..90ba762
--- /dev/null
+++ b/bash/rbashrc.in
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+# Generated from bash/rbashrc.in + bash/core/*.
+# Do not edit bash/rbashrc directly.
+
+case $- in
+  *i*) ;;
+  *) return ;;
+esac
+
+__RBASH_SCRIPT="${BASH_SOURCE[0]}"
+
+RBASH_HOME="${RBASH_HOME:-$HOME/.rbash}"
+RBASH_REMOTE="${RBASH_REMOTE:-https://sgit.k8s.astropenguin.net}"
+RBASH_REPO="${RBASH_REPO:-penguin/utils}"
+RBASH_REF="${RBASH_REF:-master}"
+RBASH_PATH="${RBASH_PATH:-bash}"
+
+RBASH_SOURCES="$RBASH_HOME/sources"
+RBASH_CONFIG="$RBASH_HOME/config"
+RBASH_ENV="$RBASH_HOME/env"
+RBASH_MERGED="$RBASH_SOURCES/merged"
+RBASH_BIN="$RBASH_HOME/bin"
+
+RHOSTNAME="<HOSTNAME>"
+RDOMAIN="<DOMAIN>"
+RCOLOR="<RCOLOR>"
\ No newline at end of file
diff --git a/bash/sources/20_fast-greps b/bash/sources/14_shortcuts_greps
similarity index 100%
rename from bash/sources/20_fast-greps
rename to bash/sources/14_shortcuts_greps
diff --git a/bash/sources/30_mysql b/bash/sources/30_mysql
deleted file mode 100755
index 1c0a766..0000000
--- a/bash/sources/30_mysql
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/bin/bash
-
-function grepmysql {
-    if [[ -z "$1" ]]; then
-        __func_head "MySQL_SERVER_NAME [WITH_OPTIONS]"
-        echo
-    else
-        if [[ -z "$2" ]]; then
-            grep -i $1 ~/.mysql_pass | awk 'BEGIN{FS=":"}{ print $2 }'
-        else
-            grep -i $1 ~/.mysql_pass | awk 'BEGIN{FS=":"}{ print $2" "$3 }'
-        fi
-    fi
-}
-
-function mysqlo () {
-    if [ -z "$1" ]; then
-        __func_head "SERVER_NAME"
-        echo
-    else
-        PASS=$(grepmysql $1 true)
-        if [ -z "$PASS" ]; then
-            echo "Server not found in config: $1"
-            return 1
-        fi
-
-        PS_SQL=$(grep -i $1 ~/.mysql_pass | awk 'BEGIN{FS=":"}{ print $4 }')
-        USER=$(grep -i $1 ~/.mysql_pass | awk 'BEGIN{FS=":"}{ print $5 }')
-
-        export MYSQL_PS1="$PS_SQL> "
-
-        shift
-
-        echo $__mysql
-        mysql -u $USER --password=$PASS $@
-        unset PS_SQL
-    fi
-}
-
-function mysqls () {
-    if [ -z "$1" ]; then
-        __func_head "[z] SERVER_NAME DATABASE_NAME SQL_FILE"
-        echo
-    else
-        GZIP=false
-		PV=false
-		_ANY=false
-        if [[ "$1" == *z* ]]; then
-            GZIP=true
-			_ANY=true
-		fi
-		if [[ "$1" == *p* ]]; then
-			PV=true
-			_ANY=true
-		fi
-		if $_ANY; then
-			shift
-		fi
-
-        USER=$(grep -i $1 ~/.mysql_pass | awk 'BEGIN{FS=":"}{ print $5 }')
-        PASS=$(grepmysql $1 true)
-
-        if [ -z "$PASS" ]; then
-            echo "Server not found in config: $1"
-            return 1
-        fi
-
-        if $GZIP; then
-			if $PV; then
-				pv $3 | gunzip | mysql -u $USER --password=$PASS -D $2
-			else
-				gunzip -c $3 | mysql -u $USER --password=$PASS -D $2
-			fi
-        else
-			if $PV; then
-				pv $3 | mysql -u $USER --password=$PASS -D $2
-			else
-				mysql -u $USER --password=$PASS -D $2 < $3
-			fi
-        fi
-    fi
-}
diff --git a/bash/tools/build-rbashrc.sh b/bash/tools/build-rbashrc.sh
new file mode 100755
index 0000000..aea24ec
--- /dev/null
+++ b/bash/tools/build-rbashrc.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+out="$root/bash/rbashrc"
+
+{
+  cat "$root/bash/rbashrc.in"
+
+  shopt -s nullglob
+
+  core_files=( "$root"/bash/core/*.bash )
+
+  if [ "${#core_files[@]}" -eq 0 ]; then
+    echo "error: no core files found under bash/core/*.bash" >&2
+    exit 1
+  fi
+
+  for f in "${core_files[@]}"; do
+    rel="${f#$root/}"
+    printf '\n\n# ---- rbash: %s ----\n\n' "$rel"
+    cat "$f"
+  done
+} > "$out"
+
+chmod +x "$out"
+echo "wrote $out"
\ No newline at end of file