Dependency management
for bash scripts.
Declare URLs in a .bashdep file. bashdep downloads them in
parallel, verifies checksums, and keeps installs idempotent with a per-directory
lockfile — no registry, no daemon, no runtime.
# why
Vendoring bash deps by hand doesn't scale
Shell projects pull helper scripts with copy-pasted curl lines —
no pinning, no integrity, no idempotency, no record of what's installed.
hand-rolled
- Re-downloads every run, or never updates
- No record of what came from where
- No checksum — trust whatever the URL served
- Serial downloads; one slow host stalls them all
- Dev-only tools mixed in with runtime deps
with bashdep
- Idempotent per source URL via
.bashdep.lock - The lockfile records every file's origin
- Opt-in
#sha256=integrity verification - Parallel downloads, tuned by
BASHDEP_JOBS @devsuffix routes tools tolib/dev/
# features
Small surface, real ergonomics
One ~800-line script. At runtime it calls only
curl/wget, awk, and POSIX builtins.
idempotent lockfile
Per-directory .bashdep.lock records each URL; re-runs skip unchanged deps, a URL bump re-downloads only that entry.
parallel downloads
Fetch concurrently (default 4, set BASHDEP_JOBS). Lockfile writes batch into one atomic rewrite per dir.
checksum verify
Append #sha256=<hex> to any URL; a mismatch fails the install and leaves no file or lockfile entry.
dev / prod split
The @dev suffix routes a dependency to lib/dev/, keeping runtime and tooling apart.
curl or wget
Uses whichever is installed, preferring curl and falling back to wget automatically.
cli + completion
Run it as a command or source it as a library. Ships bash/zsh tab completion.
lifecycle tools
list, uninstall, clean, doctor — audit and repair lockfile / filesystem drift.
ci-friendly
Every command returns a meaningful, capped count — gate a pipeline on doctor or install directly.
bash 3.2+
Runs on macOS default bash and Linux bash 4+. No associative arrays, no external deps to install.
# how it works
declare → install → locked
A single install classifies each entry, downloads them in
parallel, verifies any pins, then writes one lockfile per directory.
.bashdep classify download ×N verify .bashdep.lock ┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌───────────────┐ │ declare │──▶│ route │──▶│ curl │ wget │─▶│ sha256 │──▶│ atomic write │ │ urls │ │ dir │ │ in parallel │ │ reject≠ │ │ one per dir │ └──────────┘ └──────────┘ └──────────────┘ └──────────┘ └───────────────┘ @dev strip BASHDEP_JOBS #sha256= commit .lock
vendor bashdep
$ mkdir -p lib $ curl -fsSLo lib/bashdep …/releases/latest/download/bashdep $ chmod +x lib/bashdep
declare your .bashdep
# one URL per line · # comments · @dev · #sha256= https://github.com/TypedDevs/bashunit/releases/download/0.17.0/bashunit https://example.com/dev-tool.sh@dev https://example.com/pinned.sh#sha256=e3b0c44298fc1c149afbf…
install — and commit the lockfile
$ ./lib/bashdep install > installed 3, skipped 0, failed 0 $ git add .bashdep.lock # pin versions for collaborators
# quick start
two ways to drive it
as a cli
$ ./lib/bashdep install # from ./.bashdep $ ./lib/bashdep list # what's installed $ ./lib/bashdep doctor # detect drift $ ./lib/bashdep clean --dry-run $ source <(./lib/bashdep completion bash)
as a sourced library
#!/bin/bash set -euo pipefail source lib/bashdep bashdep::setup dir="vendor" dev-dir="local/dev" bashdep::install_from # reads ./.bashdep
# reference
cli at a glance
| command | what it does |
|---|---|
install [url…] | Install given URLs, or read them from .bashdep |
list [dir…] | List installed dependencies (path + source URL) |
uninstall <name…> | Remove deps and their lockfile entries |
clean | Remove files not recorded in the lockfile |
doctor | Report lockfile / filesystem inconsistencies |
self-update [ref] | Update bashdep itself from upstream |
completion [bash|zsh] | Print a shell completion script |
version | Print the bashdep version |
flags: --dir --dev-dir --file
--force --dry-run --silent --verbose --version
# docs
read more
api reference →
The CLI plus every bashdep:: function.
behavior →
Lockfile rules, checksums, parallelism, errors.
releasing →
How maintainers cut a tagged release.
contributing →
Project layout, toolchain, test conventions.
changelog →
What changed in each release.
source →
One script, a test suite, a release pipeline.