- Enhanced BASH Scripts
- Usage
- Library Overview
- Colors
- Script Dependencies
- Logger
- Arguments Parsing
- Common(s) Functions And Inputs
- UI: Selector
- UI: Ask for Password
- Dry-Run Wrapper System
- Hooks
- Semver - Semantic Versioning
- Git Semantic/Conventional commits
- Git Verify Commits Messages - Conventional Commits
- Git Logs
- Git Files Changes
- Self-Update
- Documentation Generator: e-docs
- Troubleshooting
- Profile BASH script execution
- Colors support in my terminal
- Emoji support in my terminal
- References
- Contributing
- License
Installation into your project with helper script:
install/upgrade to the latest version
# install into current folder/workspace
curl -sSL https://git.new/e-bash | bash -s --
# OR: install into global folder (~/.e-bash)
curl -sSL https://git.new/e-bash | bash -s -- --global installAlternatives:
# OR: install latest version
wget -qO- https://git.new/e-bash | bash -s -- install
# OR: install latest version (httpie)
http -b https://git.new/e-bash | bash -s -- installbrew install artfulbits-se/tap/e-bash# install specific version
curl -sSL https://git.new/e-bash | bash -s -- install v1.0.0
# OR: install specific version
wget -qO- https://git.new/e-bash | bash -s -- install v1.0.0
# OR: install specific version (httpie)
http -b https://git.new/e-bash | bash -s -- install v1.0.0To use e-bash utilities in your bash scripts, add this bootstrap snippet at the top:
Version A: Documented/Readable (with error handling)
# -----------------------------------------------------------------------------
# e-bash bootstrap: auto-establish E_BASH and PATH
# -----------------------------------------------------------------------------
[ -z "$E_BASH" ] && readonly E_BASH="$(
# 1. Use existing E_BASH if set
# 2. Find .scripts relative to this script
# 3. Fallback to ~/.e-bash/.scripts
if [ -n "${E_BASH+x}" ]; then
echo "$E_BASH"
elif [ -f "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../.scripts/_colors.sh" ]; then
echo "$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd ../.scripts && pwd)"
elif [ -d "$HOME/.e-bash/.scripts" ]; then
echo "$HOME/.e-bash/.scripts"
else
echo "" >&2
echo "Error: Cannot find e-bash library. Please install e-bash first." >&2
echo " Visit: https://github.com/OleksandrKucherenko/e-bash" >&2
echo "" >&2
exit 1
fi
)"
# Add gnubin to PATH (Linux/macOS compatibility)
if [[ -d "$E_BASH/../bin/gnubin" ]]; then
PATH="$E_BASH/../bin/gnubin:$PATH"
# Source _gnu.sh to create symlinks if needed
[[ -f "$E_BASH/_gnu.sh" ]] && source "$E_BASH/_gnu.sh"
fi
# Now source required modules
source "$E_BASH/_colors.sh"
source "$E_BASH/_logger.sh"
# ... add more modules as needed
# -----------------------------------------------------------------------------Version B: Compact 2-LOC (248 characters, good balance)
# 2-LOC bootstrap: E_BASH discovery + gnubin PATH
[ -z "$E_BASH" ] && readonly E_BASH="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && [[ -f ../.scripts/_colors.sh ]] && echo "$(pwd)/../.scripts" || echo "$HOME/.e-bash/.scripts")" && source "${E_BASH}/_gnu.sh" && PATH="${E_BASH}/../bin/gnubin:$PATH"
# Source modules (examples)
source "$E_BASH/_colors.sh"; source "$E_BASH/_logger.sh"Version C: Ultra-Optimized (used in e-bash scripts)
# Bootstrap: 1) E_BASH discovery (only if not set), 2) gnubin setup (always)
[ "$E_BASH" ] || { _src=${BASH_SOURCE:-$0}; E_BASH=$(cd "${_src%/*}/../.scripts" 2>&- && pwd || echo ~/.e-bash/.scripts); readonly E_BASH; }
. "$E_BASH/_gnu.sh"; PATH="$(cd "$E_BASH/../bin/gnubin" 2>&- && pwd):$PATH"
# Source modules (examples)
source "$E_BASH/_colors.sh"; source "$E_BASH/_logger.sh"Note: All versions use the same discovery order: E_BASH env var → relative .scripts/ → ~/.e-bash/.scripts fallback. Version A has full error handling; Versions B/C are more compact.
Then source the modules you need:
source "$E_BASH/_logger.sh"- Advanced logging with tag-based filteringsource "$E_BASH/_dependencies.sh"- Dependency management with version constraintssource "$E_BASH/_arguments.sh"- Command-line argument parsingsource "$E_BASH/_hooks.sh"- Declarative hooks systemsource "$E_BASH/_traps.sh"- Enhanced trap managementsource "$E_BASH/_semver.sh"- Semantic versioning supportsource "$E_BASH/_commons.sh"- Common utilities and UI componentssource "$E_BASH/_colors.sh"- Terminal color detection and ANSI definitions
See .scripts/ directory for all available modules.
git remote add -f e-bash https://github.com/OleksandrKucherenko/e-bash.git
git checkout -b e-bash-temp e-bash/master
git subtree split -P .scripts -b e-bash-scripts
git checkout master # or main - depends on your main branch in repo
git subtree merge --prefix .scripts e-bash-scripts --squashUpgrade .scripts to the latest version:
git fetch e-bash master
git checkout e-bash-temp && git reset --hard e-bash/master
git subtree split -P .scripts -b e-bash-scripts
git checkout <your-main-branch>
git subtree pull --prefix .scripts e-bash-scripts --squashrefs:
source ".scripts/_colors.sh"
echo -e "${cl_red}Hello World${cl_reset}"source ".scripts/_dependencies.sh"
dependency bash "5.*.*" "brew install bash"
dependency direnv "2.*.*" "curl -sfL https://direnv.net/install.sh | bash"
dependency shellspec "0.28.*" "brew install shellspec"
optional kcov "42" "brew install kcov"
dependency shellcheck "0.9.*" "curl -sS https://webi.sh/shellcheck | sh"
dependency shfmt "3.*.*" "curl -sS https://webi.sh/shfmt | sh"
dependency watchman "2023.07.*.*" "brew install watchman"
# different return codes for success and failure
dependency watchman "2023.07.*.*" "brew install watchman" && echo "OK!" || echo "FAIL!"
# optional always return success
optional watchman "2023.07.*.*" "brew install watchman" && echo "OK!" || echo "never happens!"
# Allow of HEAD or stable versions of the watchman tool
wHead=$(dependency watchman "HEAD-[a-f0-9]{1,8}" "brew install watchman")
wStab=$(dependency watchman "2024.*.*.*" "brew install watchman")
echo "$wHead" | grep 'Error' &>/dev/null && echo "$wStab" || echo "$wHead"Quick Start Guide | API Reference
Requirements:
- zero dependencies, pure BASH (optional: _colors.sh)
- prefix for all logger messages
- work in pipe mode (forward logs to the named pipe)
- write logs to pipe; single line or multiple lines in '|' pipe mode
- read logs from the named pipe and output to the console (or file).
- redirect logs to file/stream/pipe/tty
- support prefix for each log message
- listen to DEBUG environment variable for enabling/disabling logs
- enable/disable log by tag name or tag name prefix (support wildcards)
- execute command with logging the command and it parameters first, ref: echo-eval - use DRYRUN functionality for that
- can be easily self-made, ref: echo-eval, ee
source ".scripts/_logger.sh"
logger common "$@" # declare echo:Common and printf:Common functions, tag: common
logger debug "$@" # declare echo:Debug and printf:Debug functions, tag: debug
echo:Common "Hello World" # output "Hello World" only if tag common is enabled
export DEBUG=* # enable logger output for all tags
export DEBUG=common # enable logger output for common tag only
export DEBUG=*,-common # enable logger output for all tags except common
# advanced functions
config:logger:Common "$@" # re-configure logger enable/disable for common tag
# echo in pipe mode
find . -type d -max-depth 1 | log:Common
# echo in output redirect
find . -type d -max-depth 1 >log:Common
# more samples of usage are in `demos/demo.logs.sh` fileComplete demo: Logger Demo
Requirements:
- zero dependencies, pure BASH
- support short and long arguments
- support default values
- support required arguments
- support aliases for arguments
- support destination variables for argument
- compose help documentation from arguments definition
# pattern: "{argument_index},-{short},--{alias}={output_variable}:{default_initialize_value}:{reserved_args_quantity}"
# example: "-h,--help=args_help:true:0", on --help or -h set $args_help variable to true, expect no arguments;
# example: "$1,--id=args_id::1", expect first unnamed argument to be assigned to $args_id variable; can be also provided as --id=123
export ARGS_DEFINITION="-h,--help -v,--version=:1.0.0"
export ARGS_DEFINITION+=" --debug=DEBUG:*"
# will automatically parse script arguments with definition from $ARGS_DEFINITION global variable
source "$E_BASH/_arguments.sh"
# check variables that are extracted
echo "Is --help: $help"
echo "Is --version: $version"
echo "Is --debug: $DEBUG"
# advanced run. parse provided arguments with definition from $ARGS_DEFINITION global variable
parse:arguments "$@"More details: Arguments Parsing, Demo script, API Reference.
Complete Documentation | API Reference
source ".scripts/_commons.sh"
# Find git repository root (handles regular repos, worktrees, submodules)
repo_root=$(git:root)
repo_type=$(git:root "." "type") # regular, worktree, or submodule
# Find configuration file hierarchy (similar to c12/cosmiconfig)
configs=$(config:hierarchy ".eslintrc" "." "git" ",.js,.json,.yaml")
# Returns files in order: root → current (for proper config merging)
# XDG-compliant config discovery
configs=$(config:hierarchy:xdg "nvim" "init.vim" "." "home")
# Searches: project configs → ~/.config/nvim → /etc/xdg/nvim → /etc/nvim
# Extract parameter from global env variable OR from secret file (file content)
env:variable:or:secret:file "new_value" \
"GITLAB_CI_INTEGRATION_TEST" \
".secrets/gitlab_ci_integration_test" \
"{user friendly message}"
echo "Extracted: ${new_value}"source ".scripts/_commons.sh"
# Select value from short list of choices
declare -A -g connections && connections=(["d"]="production" ["s"]="cors-proxy:staging" ["p"]="cors-proxy:local")
echo -n "Select connection type: " && tput civis # hide cursor
selected=$(input:selector "connections") && echo "${cl_blue}${selected}${cl_reset}"source ".scripts/_commons.sh"
# Usage:
echo -n "Enter password: "
password=$(input:readpwd) && echo "" && echo "Password: $password"Safe command execution with three-mode operation: normal, dry-run (preview), and undo/rollback. Provides automatic logging, exit status tracking, and flexible per-command configuration.
source "$E_BASH/_dryrun.sh"
# Create wrappers for commands
dry-run git docker kubectl
# Normal, safe operation, does not mutate anything
run:git status
# Normal mode - execute commands, if no DRY_RUN set
dry:git pull origin main
dry:docker build -t app .
# Normal mode - Register rollback command, executed only when UNDO_RUN is set
rollback:kubectl delete deployment app
# Dry-run mode - preview operation in terminal without executing it
DRY_RUN=true dry:git pull origin main
# Undo mode - execute rollbacks, only when UNDO_RUN=true
UNDO_RUN=true rollback:git reset --hard
function rollback_fn() {
echo "Cleaning up..."
echo "Possible execution of multiple commands..."
}
# Rollback via special function
rollback:func rollback_fnThree Execution Modes:
| Mode | DRY_RUN | UNDO_RUN | Normal Commands | Rollback Commands |
|---|---|---|---|---|
| Normal | false | false | Execute | Dry-run (safe) |
| Dry-run | true | false | Dry-run | Dry-run |
| Undo | false | true | Dry-run | Execute |
Features:
- ✅ Color-coded logging with exit status (
execute:,dry run:,undoing:) - ✅ Command-specific overrides (
DRY_RUN_GIT=false, pattern:DRY_RUN_*) - ✅ Silent mode support (
SILENT_GIT=true, pattern:SILENT_*) - ✅ Function-based rollbacks (
rollback:func cleanup_fn) - ✅ Variable precedence: command-specific → global → default
More details: Dry-Run Wrapper System, Demo script, API Reference.
Add extension points to any bash script with minimal changes. Hook implementations live in external files - your script just declares and triggers them.
Before (your existing script):
#!/bin/bash
echo "Starting deployment..."
deploy_application
echo "Done."After (several lines added):
#!/bin/bash
+ export HOOKS_DIR=".hooks" # Default is 'ci-cd'
+ source "$E_BASH/_hooks.sh"
+ hooks:declare begin deploy end
+ hooks:do begin
echo "Starting deployment..."
deploy_application
+ hooks:do deploy "$VERSION"
echo "Done."
+ hooks:do endNow add any functionality via external scripts in .hooks/ folder following pattern in naming {hook_name}-{purpose}.sh:
hook_name is one of the declared hooks: begin, deploy, end; purpose - is your user-friendly name for the hook.
Hooks are executed in alphabetical order, and you can declare multiple hooks for the same hook point/name.
.hooks/begin-otel-trace.sh - OpenTelemetry tracing:
#!/bin/bash
export TRACE_ID=$(openssl rand -hex 16)
curl -s "${OTEL_ENDPOINT}/v1/traces" -d "{...span data...}" &>/dev/null.hooks/deploy-slack-notify.sh - Slack notifications:
#!/bin/bash
curl -s "$SLACK_WEBHOOK" -d "{\"text\":\"Deploying $1\"}".hooks/end-metrics.sh - Metrics export:
#!/bin/bash
echo "deployment.duration=$SECONDS" | nc -u metrics.local 8125Custom hooks directory per script:
HOOKS_DIR=".hooks/$(basename "$0" .sh)" # .hooks/my-script/
source "$E_BASH/_hooks.sh"or maybe Hooks Documentation or API Reference;
Demos: Intro, Multiple Hooks, Nested Hooks, Hooks with Logs, CI Hooks Demo, CI Hooks with Middlewar
Requirements:
- parse version code, according to semver specification
- compare version code
- verify version constraints
- compose version code from array of segments
source ".scripts/_semver.sh"
# verify that version is passing the constraints expression
semver:constraints "1.0.0-alpha" ">1.0.0-beta || <1.0.0" && echo "$? - OK!" || echo "$? - FAIL!" # expected OK
# more specific cases
semver:constraints:simple "1.0.0-beta.10 != 1.0.0-beta.2" && echo "OK!" || echo "$? - FAIL!"
# parse and recompose version code
semver:parse "2.0.0-rc.1+build.123" "V" \
&& for i in "${!V[@]}"; do echo "$i: ${V[$i]}"; done \
&& semver:recompose "V"
# test version code
echo "1" | grep -E "${SEMVER_LINE}" --color=always --ignore-case || echo "OK!"Set of git helpers are implemented.
# compute semantic version from git history
bin/git.semantic-version.shSemantic Version History:
| Commit | Message | Tag | Version Change | Diff |
|---|---|---|---|---|
| cb10f67 | imported version-up.sh script | - | 0.0.1 → 0.0.1 | +0.0.0 |
| c75cdab | added several demos (#4) | - | 0.0.1 → 0.0.1 | +0.0.0 |
| 32b1951 | Update README.md | v1.0.0 | 0.0.1 → 1.0.0 | =1.0.0 |
| 3e6d934 | small patch (#5) | v1.0.1-alpha.1 | 1.0.0 → 1.0.1-alpha.1 | =1.0.1-alpha.1 |
| d08724e | Self update functionality (#6) | - | 1.0.1-alpha.1 → 1.0.1-alpha.1 | +0.0.0 |
| dffc346 | fix: kcov docker image use (#9) | - | 1.0.1-alpha.1 → 1.0.2-alpha.1 | +0.0.1 |
| b982126 | wip: log to file and stderr | - | 1.0.2-alpha.1 → 1.0.2-alpha.1 | +0.0.0 |
| 8649d55 | Document args (#10) | v1.1.0 | 1.0.2-alpha.1 → 1.1.0 | =1.1.0 |
| 21ba265 | Update README.md | - | 1.1.0 → 1.1.0 | +0.0.0 |
| b00a1d0 | fix: installation script global and local installation scenarios (#16) | - | 1.1.0 → 1.1.1 | +0.0.1 |
| 82a5c35 | wip: updated dependencies | - | 1.1.1 → 1.1.1 | +0.0.0 |
| 60fcd80 | wip: code review of another PR (#18) | - | 1.1.1 → 1.1.1 | +0.0.0 |
| b0901ab | test: add comprehensive test coverage for version-up v2 (TDD approach) (#19) | - | 1.1.1 → 1.1.2 | +0.0.1 |
| 13f8feb | feat: add git semantic version calculator script (#20) | - | 1.1.2 → 1.2.0 | +0.1.0 |
| 2b4b34f | Fix/coverage unknown status (#21) | - | 1.2.0 → 1.2.0 | +0.0.0 |
| 7cc5870 | ci: Add CI cache for Homebrew installations (#25) | - | 1.2.0 → 1.2.1 | +0.0.1 |
| fbdee5c | feat: add mise tool support to e-bash install script (#23) | - | 1.2.1 → 1.3.0 | +0.1.0 |
| b64d60b | feat: add trap management module with multiple handler support | - | 1.3.0 → 1.4.0 | +0.1.0 |
| 1e2e98f | fix: resolve CI test failures for trap module | - | 1.4.0 → 1.4.1 | +0.0.1 |
| e854d5d | fix: trap:push without arguments now correctly snapshots all signals | - | 1.4.1 → 1.4.2 | +0.0.1 |
| c031c50 | fix: resolve CI test failures for trap module | - | 1.4.2 → 1.4.3 | +0.0.1 |
| cd3eb44 | fix: make logger mocks produce output for test assertions | - | 1.4.3 → 1.4.4 | +0.0.1 |
| 6af95a2 | fix: redirect mock logger output to stderr matching e-bash convention | - | 1.4.4 → 1.4.5 | +0.0.1 |
| 63797bf | fix: resolve ShellSpec syntax errors in trap tests | - | 1.4.5 → 1.4.6 | +0.0.1 |
| 244b15b | fix: redirect stderr to /dev/null for trap setup commands in tests | - | 1.4.6 → 1.4.7 | +0.0.1 |
Summary:
Total commits processed: 55
Version changes:
Major (breaking): 0
Minor (features): 3
Patch (fixes): 11
Tag (assigned): 3
None (ignored): 38
Final Version: 1.4.7
bin/git.verify-all-commits.sh❯ bin/git.verify-all-commits.sh
🔍 Gathering commit history...
🔍 Checking 56 commits for Conventional Commit compliance...
Progress: 0.........10.........20.........30.........40.........50.....
❌ 34 commit(s) failed:
🔴 Commit: bf2da247, Author: Oleksandr, Date: 2025-11-08
Message: "Fix and optimize Codecov configuration (#22)"
🔴 Commit: 2b4b34f9, Author: Oleksandr, Date: 2025-11-08
Message: "Fix/coverage unknown status (#21)"
// ...TRIMMED...
🔴 Commit: cb10f677, Author: Oleksandr Kucherenko, Date: 2023-10-03
Message: "imported version-up.sh script"
💡 Conventional Commit format: type(scope): description
Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
Use ! for breaking changes: feat!: breaking change
Reference: https://www.conventionalcommits.org/
# show last 10 commits messages
bin/git.log.sh 25Display all changed files from N last commits, in PLAIN or TREE view.
Script also uses links integration into terminal, on click should be open vscode.
# show changed files in 1 last commit, and show it as a tree
bin/git.files.sh 1 --treePurpose: The self-update functionality allows any project that uses the e-bash scripts library to automatically detect source updates and update library files file-by-file. This is designed specifically for BASH scripts built on top of the e-bash library.
Main Usage Pattern: The recommended approach is to invoke self-update when your script exits, ensuring the library stays current for the next execution:
# Using e-bash traps module (recommended)
source ".scripts/_self-update.sh"
source ".scripts/_traps.sh"
function on_exit_update() {
self-update '^1.0.0'
}
trap:on on_exit_update EXIT
# Or using built-in trap (simpler, but less flexible)
trap "self-update '^1.0.0'" EXITHow It Works:
- Maintains a local git repository at
~/.e-bash/with multiple version worktrees - Creates symbolic links from your project's
.scripts/files to version-specific files - Performs file-by-file updates with automatic backup creation
- Verifies updates using SHA1 hash comparison
- Supports rollback to previous versions or backup files
Requirements:
- detect a new version of the script
- download multiple versions into folder and do a symbolic link to a specific version
- download from GIT repo (git clone)
- keep MASTER as default, extract version tags as sub-folders
- download from GIT repo release URL (tar/zip archive)
- extract archive to a version sub-folder
- rollback to previous version (or specified one)
- rollback to latest backup file (if exists)
- partial update of the scripts, different versions of scripts from different version sub-folders
- developer can bind file to a specific version by calling function
self-update:version:bind
- developer can bind file to a specific version by calling function
- verify SHA1 hash of the scripts
- compute file SHA1 hash and store it in *.sha1 file
- understand version expressions
-
latest- latest stable version (no pre-release tags) -
*ornext- any highest version tag (INCLUDING: alpha, beta, rc etc) -
branch:{any_branch}- update from any branch name -
tag:{any_tag}- update to specific tag -
>,<,>=,<=,~,!=,||- comparison syntax -
1.0.0or=1.0.0- exact version -
~1.0.0- version in range >= 1.0.x, patch releases allowed -
^1.0.0- version in range >= 1.x.x, minor & patch releases allowed -
>1.0.0 <=1.5.0- version in range> 1.0.0 && <= 1.5.0 -
>1.0.0 <1.1.0 || >1.5.0- version in range(> 1.0.0 < 1.1.0) || (> 1.5.0)
-
refs:
source ".scripts/_self-update.sh"
# check for version update in range >= 1.0.x, stable versions
# try to update itself from https://github.com/OleksandrKucherenko/e-bash.git repository
self-update "~1.0.0" # patch releases allowed
self-update "^1.0.0" # minor releases allowed
self-update "> 1.0.0 <= 1.5.0" # stay in range
# update specific file to latest version tag
self-update "latest" ".scripts/_colors.sh" # latest stable
self-update "*" ".scripts/_colors.sh" # any highest version tag
# update specific file to MASTER version (can be used any branch name)
self-update "branch:master" ".scripts/_colors.sh"
self-update "tag:v1.0.0" ".scripts/_colors.sh"
# bind file to a specific version
self-update:version:bind "v1.0.0" ".scripts/_colors.sh"
# TBD
# INTEGRATION EXAMPLE
# do self-update on script exit
trap "self-update '^1.0.0'" EXIT
# OR:
function __exit() {
# TODO: add more cleanup logic here
self-update '^1.0.0'
}
trap "__exit" EXITAutomated documentation generator that extracts documentation from ## comments in your bash scripts and generates GitHub-flavored Markdown.
# Generate docs for all scripts in .scripts/
bin/e-docs.sh
# Generate docs for a specific file
bin/e-docs.sh .scripts/_logger.sh# rollback with use of backup file(s)
source ".scripts/_self-update.sh" && self-update:rollback:backup "${full_path_to_file}"
# rollback to specific version
source ".scripts/_self-update.sh" && self-update:rollback:version "v1.0.0" "${full_path_to_file}"# print timestamp for each line of executed script
PS4='+ $(gdate "+%s.%N ($LINENO) ")' bash -x bin/version-up.v2.sh
# save trace to file
PS4='+ $(echo -n "$EPOCHREALTIME [$LINENO]: ")' bash -x bin/version-up.v2.sh 2>trace.log
# process output to more user-friendly format: `execution_time | line_number | line_content`
PS4='+ $(echo -n "$EPOCHREALTIME [$LINENO]: ")' bash -x bin/version-up.v2.sh 2>trace.log 1>/dev/null && cat trace.log | bin/profiler/tracing.sh
# profile script execution and print summary
bin/profiler/profile.sh bin/version-up.v2.sh- ref1: https://itecnote.com/tecnote/r-performance-profiling-tools-for-shell-scripts/
- ref2: https://www.thegeekstuff.com/2008/09/bash-shell-take-control-of-ps1-ps2-ps3-ps4-and-prompt_command/
# print all colors for easier selection
demos/demo.colors.shRun this command if you want to see how your terminal setup support emojis. Usually Windows WSL2 teminals has very limited support enabled by default, so you should be carefull when selecting emojis for your scripts.
demos/demo.emojis.sh- PV - https://manpages.ubuntu.com/manpages/focal/man1/pv.1.html
- https://catern.com/posts/pipes.html
- https://stackoverflow.com/questions/238073/how-to-add-a-progress-bar-to-a-shell-script
- bash-core, trap enhancement
- bash-bastion BASH helpers
- https://github.com/dylanaraps/writing-a-tui-in-bash
- bash-toml TOML Support (also INI files support!)
- Pure Bash Bible
Conventions and folder structure: docs/public/conventions.md
- High-level scripts should be in their own
binORdemos - Git helpers
- GitLab's helper scripts (work with branches, forks, submodules)
- Globals module (declarative way of defining script dependencies to global environment variables)
- Logs monitoring documentation (different streams/files/tty for different information: info, debug, telemetry, dependencies)
- Copyright headers composing/parsing (extract from the file, update, insert)
Note: alternative Unit Test Frameworks, Bats - BATS core
brew install direnv
brew install shellcheck
brew install shfmt
brew install shellspec
brew install kcov# make tool required Python in hidden dependencies
# ref1: https://docs.astral.sh/uv/guides/install-python/
# ref2: https://github.com/astral-sh/uv
uv python install
# alternative: pyenv install 3.13.2 && pyenv global 3.13.2
# run all unit tests on file change
watchman-make -p 'spec/*_spec.sh' '.scripts/*.sh' --run "shellspec"
# run failed only unit tests on file change
watchman-make -p 'spec/*_spec.sh' '.scripts/*.sh' --run "shellspec --quick"
# run failed only unit tests on file change without coverage
watchman-make -p 'spec/*_spec.sh' '.scripts/*.sh' --run "shellspec --quick --no-kcov --"
# Multiple Jobs (parallel execution)
# shellspec -j 8
# 40.34s user 10.62s system 38% cpu 2:12.97 total
# shellspec -j 4
# 40.35s user 10.28s system 40% cpu 2:03.77 total






