A convention-based Bash framework that turns .xsh files into @-prefixed functions with auto-generated CLI help. No compile step — everything is sourced at runtime.
- Bash Framework — 120+ ready-to-use utility functions.
- Compatible with Linux, macOS, and Android Shell.
- Lazy-loads functions on first call — no startup cost for unused utilities.
- Auto-generates CLI help and usage from source comments.
- Solves cross-platform shell quirks (e.g.
sed -ion Linux vs. macOS). See@sed
- No new language or syntax to learn — it's just Bash.
- No additional runtime dependencies.
- Rich stdlib: strings, logging, user input, file I/O, date/time, testing, and more.
- Drop-in help generation from
##doc comments in source.
Scaffold a new project with a single command:
./bashx _bashx init project {BASHX_VERSION} {PROJECT_PATH}BASHX_VERSION— a tag from this repositoryPROJECT_PATH— script name or full path
Examples:
./bashx _bashx init project v3.2.0 my-app
./bashx _bashx init project v3.2.0 ~/projects/my-script.sh1) Add the following bootstrap block at the top of your script:
#!/usr/bin/env bash
###############################################################################
# BashX | https://github.com/reduardo7/bashx
set +ex;export BASHX_VERSION="v3.2.0"
(export LC_CTYPE=C;export LC_ALL=C;export LANG=C;set -e;x() { s="$*";echo "# Error: ${s:-Installation fail}" >&2;exit 1;};d=/dev/null;[ ! -z "$BASHX_VERSION" ] || x BASHX_VERSION is required;export BASHX_DIR="${BASHX_DIR:-${HOME:-/tmp}/.bashx/$BASHX_VERSION}";if [ ! -d "$BASHX_DIR" ];then u="https://raw.githubusercontent.com/reduardo7/bashx/$BASHX_VERSION/src/setup.sh";if type wget >$d 2>&1;then sh -c "$(wget -q $u -O -)" || x;elif type curl >$d 2>&1;then sh -c "$(curl -fsSL $u)" || x;else x wget or curl are required. Install wget or curl to continue;fi;fi) || exit $?
. "${HOME:-/tmp}/.bashx/${BASHX_VERSION}/src/init.sh"
###############################################################################See /bashx
2) Write your code.
3) Optionally, add the following at the end to expose actions as a CLI:
@app.run-
Create a project folder:
touch bashx-example cd bashx-example -
Create the main script:
vim my-app
-
Writhe the content:
#!/usr/bin/env bash ############################################################################### # BashX | https://github.com/reduardo7/bashx set +ex;export BASHX_VERSION="v3.2.0" (export LC_CTYPE=C;export LC_ALL=C;export LANG=C;set -e;x() { s="$*";echo "# Error: ${s:-Installation fail}" >&2;exit 1;};d=/dev/null;[ ! -z "$BASHX_VERSION" ] || x BASHX_VERSION is required;export BASHX_DIR="${BASHX_DIR:-${HOME:-/tmp}/.bashx/$BASHX_VERSION}";if [ ! -d "$BASHX_DIR" ];then u="https://raw.githubusercontent.com/reduardo7/bashx/$BASHX_VERSION/src/setup.sh";if type wget >$d 2>&1;then sh -c "$(wget -q $u -O -)" || x;elif type curl >$d 2>&1;then sh -c "$(curl -fsSL $u)" || x;else x wget or curl are required. Install wget or curl to continue;fi;fi) || exit $? . "${HOME:-/tmp}/.bashx/${BASHX_VERSION}/src/init.sh" ############################################################################### @Actions.action1() { # \\n Action without arguments @log " Action 1 Multi-Line " } @Actions.action2() { # <param1> <param2?> \\n Action with arguments\\n\\tdescription second line\\nother line local param1="$1" local param2="$2" [ "$param1" != 'asd' ] && @throw.invalidParam param1 @log Action 2 @log Param1: $1 @log Param2: $2 } @app.run
-
Execute:
chmod a+x my-app ./my-app
Output:
ℹ️ +--------------+ ℹ️ | BashX v1.0 | ℹ️ +--------------+ ℹ️ ℹ️ +----------------+ ℹ️ | Help & Usage | ℹ️ +----------------+ ℹ️ ℹ️ my-app action1 ℹ️ Action without arguments ℹ️ ℹ️ my-app action2 param1 [param2] ℹ️ Action with arguments ℹ️ description second line ℹ️ other line ℹ️
--> project-directory-name # Optional. Container directory.
| #
+-> my-script-name # Required. Main script.
| #
+-> .my-script-name.env # Optional. Config file.
| #
+-> my-script-name.src/ # Optional. Sources.
| #
+-> actions/ # Optional. Actions scripts.
| | #
| +-> [group...] # Script group. Can be multi-level.
| | | #
| | +-> [name].xsh # Test script into group example... (Use with @group.name)
| | #
| +-> [action-name].xsh # Test script example...
| | #
| +-> * # Test script example...
| #
+-> tests/ # Optional. Test scripts.
| | #
| +-> [test-name].xsh # Test script example...
| | #
| +-> * # Test script example...
| #
+-> utils/ # Optional. Utils scripts.
| | #
| +-> [util-name].xsh # Test script example...
| | #
| +-> * # Test script example...
| #
+-> events/ # Optional. Events scripts. Executed in next order:
| | #
| +-> invalid-action.xsh # Optional. Triggered on invalid action called.
| | #
| +-> ready.xsh # Optional. Triggered on ready.
| | #
| +-> start.xsh # Optional. Triggered on start the selected action.
| | #
| +-> error.xsh # Optional. Triggered on error (exit code != 0).
| | #
| +-> finish.xsh # Optional. Triggered on execution finished.
| #
+-> resources/ # Optional. Resources files.
| #
+-> [resource].[ext] # Resource file...
| #
+-> * # Resource file...
Valid events options constant: BX_EVENTS_OPTS.
| Reference | Description |
|---|---|
| docs/ | Full utility, action, and testing reference |
| docs/testing.md | @@assert.* testing framework |
| docs/actions.md | Public and framework actions |
| src/README.md | Source directory structure |
Print inline development docs:
./bashx _dev-docList BashX scaffolding commands:
./bashx _bashxSet to 1 to disable all BashX output colors (@style becomes a no-op).
BASHX_COLORS_DISABLED=1 ./bashxechois reserved for function return values (stdout is treated as data).- Use
@logfor informational messages,@log.warnfor warnings,@log.alertfor alerts.
- Use
@app.exitto exit cleanly. - Use
@app.errorto print an error message and exit with a non-zero code.
Avoid calling @-functions inside set -x blocks — the DEBUG trap interacts badly with nested functions.
( set -x
echo my test # plain commands only
)set -x
echo my test
set +xEvents fire in this order:
invalid-action.xsh— triggered if an unrecognised action was called.ready.xsh— triggered when initialisation is complete.start.xsh— triggered before a valid action runs.error.xsh— triggered when an error occurs (exit code ≠ 0).finish.xsh— triggered after execution finishes.
Constant for valid event names: BX_EVENTS_OPTS.
Run the test suite inside a container (mirrors CI):
./bashx _run-tests-docker # ubuntu + debian:8
./bashx _run-tests-all # Docker + localOr run a container manually:
docker run --rm \
-v $(pwd):/root/.bashx/master:ro \
-v $(pwd):/app:ro \
-w '/app' \
-ti ubuntu '/app/bashx'Add this modeline at the end of every .xsh file for correct syntax highlighting and formatting:
# vim: filetype=sh tabstop=2 softtabstop=0 expandtab shiftwidth=2 smarttab
| Prefix | Purpose |
|---|---|
BX_* |
Readonly internal framework constants (do not assign) |
BASHX_* |
User-configurable settings (set in .env or before sourcing) |