version: 0.0.96
description: bashy handles bash configuration for you
website: https://veltzer.github.io/bashy
Bashy is bash based system to enable you control of your bash with precision and elegance. It is plugin based and allows for easy extension.
First clone the repository into your home directory:
git clone --branch master --depth 1 https://github.com/veltzer/bashy.git ~/.bashy && rm -rf ~/.bashy/.gitThen edit ~/.bashrc and add the following line as the last line:
source ~/.bashy/bashy.shIn my own setup this is the only line I have in my ~/.bashrc
If you develop bashy rather than just use it, clone the repository somewhere else and install from there:
./scripts/install_in_home.bashThat copies only what is needed at runtime, listed in .includes, and it is
incremental: it prints the files that changed and copies nothing else. --delete
prunes anything in ~/.bashy that is no longer part of the install, so a renamed or
removed plugin does not linger.
To check whether the running ~/.bashy still matches your checkout:
bashy_check_deploymentJust add this line before sourcing bashy:
set -o xtraceTo see all errors use:
bashy_errorsTo get debug messages you can create a ~/.bashy.config and put the following content into it:
readonly BASHY_DEBUG=0
To check the status of the core of Bashy use:
bashy_status_coreTo check the status of plugins of Bashy use:
bashy_status_pluginsTo disable or enable a plugins or to change the order in which
they are applied just edit ~/.bashy.list
# this file supports hash comments
by_host
meta
path_mine
-path_pycharm_add
pylogconf
To reread the plugins use:
bashy_load_pluginsTo reinit Bashy when a new version is installed or pulled:
bashy_initBashy plugins may never fail a command (all commands need to return 0)
Bashy plugins need to set a variable passed by reference to either 0 or 1.
Here is the most basic plugin:
function _activate_hello_plugin() {
local -n __var=$1
# this means everything was ok
__var=0
}
register _activate_hello_pluginA prompt plugin registers a function that runs after every command you type, not once at startup. Register it from your activation function:
function prompt_hello() {
# runs on every prompt
:
}
function _activate_prompt_hello() {
local -n __var=$1
local -n __error=$2
_bashy_prompt_register prompt_hello
__var=0
}
register_interactive _activate_prompt_helloBecause it runs that often, speed is the whole design constraint. A prompt function that forks once costs a few milliseconds every single command, and there are nine prompt plugins here, so it adds up quickly. Do not run a program if a shell builtin or an already exported variable will do.
If you need to know whether the current directory is inside a git repository, call
git_is_inside rather than running git yourself. It remembers the answer per
directory, which took about 28 ms off every prompt when the seven plugins that ask
were each forking their own git rev-parse. Call git_is_inside_flush if a
repository appears or disappears under a directory you are already in.
Registration prepends, so prompt functions run in reverse registration order: a
plugin listed later in bashy.list gets to set PS1 before an earlier one.
Do not run a completion command directly at activation time. Every one of those is
a process spawn on every shell you open, and they added up to about a second here.
Use bashy_completion instead, which runs the command once and caches the result:
# instead of: source <(minikube completion bash)
bashy_completion minikube minikube completion bashThe first argument is the tool whose binary keys the cache, the rest is the command
to run. The cache lives under ${XDG_CACHE_HOME:-~/.cache}/bashy/completions and is
keyed on the size and mtime of the tool, so upgrading the tool regenerates it by
itself. bashy_completion_clean drops the cache.
This is for completion output only. zoxide init, starship init and friends emit
shell setup that may embed per session state, so those keep running live.
Install functions are named _install_<name> and should never hardcode a version
number: always ask the project what its latest release is. The core modules provide
the pieces so that every plugin behaves and reports the same way.
function _install_hello() {
local release_json
bashy_github_release "someorg/hello" release_json || return
latest_version=$(bashy_github_version "${release_json}")
folder="${HOME}/install/binaries"
executable="${folder}/hello"
# an empty installed version means "not installed yet"
installed_version=""
if [ -x "${executable}" ]
then
installed_version=$("${executable}" --version 2>/dev/null)
fi
# prints one of the three standard lines and says whether there is work to do
if bashy_install_check "hello" "${installed_version}" "${latest_version}"
then
return
fi
local download_file
bashy_github_asset "${release_json}" "_linux_amd64\\.tar\\.gz$" download_file || return
bashy_install_download "${download_file}"
local tar
bashy_download "${download_file}" tar || return
# verify whenever the project publishes checksums
local checksums
bashy_github_asset "${release_json}" "checksums\\.txt$" checksums || return
bashy_verify_sha256 "${tar}" "${checksums}" || return
rm -f "${executable}"
bashy_install_extract "${tar}" "${folder}" hello
}
function _uninstall_hello() {
bashy_uninstall_binary "hello"
}The helpers involved:
| function | purpose |
|---|---|
bashy_install_check <name> <installed> <latest> |
print the standard install/upgrade/up to date line, return 0 when there is nothing to do |
bashy_install_download <url> |
report the artifact about to be fetched |
bashy_github_release <owner/repo> [out] |
fetch the latest release json |
bashy_github_version <json> [prefix] |
tag name with the prefix (default v) stripped |
bashy_github_asset <json> <regex> [out] |
the single asset url matching a regex, fails on an ambiguous match |
bashy_download <url> [out] |
download through the cache, revalidating against the origin |
bashy_verify_sha256 <file> <url or digest> |
check a download against a published sha256 |
bashy_install_extract <archive> <folder> [members...] |
unpack and stamp with the install time rather than the archive mtime |
bashy_uninstall_binary <name> [path] |
remove a single binary from ~/install/binaries |
bashy_uninstall_directory <name> <dir...> |
remove the directory tree(s) a plugin installed |
Downloads are cached under ${XDG_CACHE_HOME:-~/.cache}/bashy/downloads, overridable
with BASHY_DOWNLOAD_CACHE. Cached files are revalidated with the origin, so a
rolling latest asset that keeps one filename forever is still refetched when it
changes upstream. Use bashy_download_clean to drop the cache.
Never pipe a remote script into a shell when the project ships a release asset that can be downloaded and verified instead.
The modules in core are loaded in the order listed by bashy_core_order in
bashy.sh, not alphabetically. The list runs from the standalone modules to the
ones built on top of them, so a module may call into anything loaded before it and
does not have to source its own dependencies.
When adding a core module, put its name in that list at a point where everything it uses is already loaded. A module left out of the list is still loaded, after all the named ones.
Plugin activation is not timed unless you ask for it. To see where shell startup
time goes, put this in ~/.bashy.config:
readonly BASHY_PROFILE=0then open a shell and run bashy_status_plugins.
You can activate various plgins via the ~/.bashy.config file.
Here is an example:
readonly ENCFS_ENABLED=true
readonly ENCFS_FOLDER_CLEAR="${"${HOME}"}/insync.real"
readonly ENCFS_FOLDER_ENCRYPTED="${"${HOME}"}/insync/encrypted"
readonly ENCFS_PASSWORD=XXXXXXXX
readonly PROXY_ENABLED=falseThis is a bash file and so you can overwrite values by using conditionals so:
if [ "$HOSTNAME" = "ion" ]
then
readonly PROXY_ENABLED=true
readonly PROXY_HTTP="http://proxy.corp.com:8080"
readonly PROXY_HTTPS="http://proxy.corp.com:8080"
readonly PROXY_NO="localhost,.corp.com"
fi- https://github.com/Bash-it/bash-it
- https://github.com/ohmyzsh/ohmyzsh
- https://github.com/ohmybash/oh-my-bash
- https://github.com/nojhan/liquidprompt
- https://github.com/daniruiz/dotfiles
- https://github.com/Gkiokan/.pimp-my-bash
- https://github.com/brujoand/sbp
- https://www.freecodecamp.org/news/jazz-up-your-bash-terminal-a-step-by-step-guide-with-pictures-80267554cb22/
- https://medium.com/@mandymadethis/pimp-out-your-command-line-b317cf42e953
- https://www.maketecheasier.com/customise-bash-prompt-linux/
- https://www.computerworld.com/article/2833199/3-ways-to-pimp-your-bash-console.html
Mark Veltzer, Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026
