{"id":13537193,"url":"https://github.com/kigster/bashmatic","last_synced_at":"2025-10-07T23:56:46.332Z","repository":{"id":37929490,"uuid":"160895837","full_name":"kigster/bashmatic","owner":"kigster","description":"Optimized for humans, 900+ BASH DSL functions for all walks of life. Über Toölkit for über geeks and UNIX command line power users. Visit https://bashmatic.dev for more info..","archived":false,"fork":false,"pushed_at":"2025-09-20T02:47:50.000Z","size":61629,"stargazers_count":166,"open_issues_count":4,"forks_count":19,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-10-06T20:56:15.526Z","etag":null,"topics":["ascii-graphics","automation","bash","functions","helpers","installation","library","scripting","ui","ui-components"],"latest_commit_sha":null,"homepage":"https://bashmatic.dev","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kigster.png","metadata":{"files":{"readme":"README.adoc","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"kigster","patreon":"polygroovers","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2018-12-08T02:21:22.000Z","updated_at":"2025-09-06T03:59:15.000Z","dependencies_parsed_at":"2024-01-19T17:28:20.750Z","dependency_job_id":"dcd973de-2c9f-4d35-85d2-3333a316f2bb","html_url":"https://github.com/kigster/bashmatic","commit_stats":null,"previous_names":[],"tags_count":64,"template":false,"template_full_name":null,"purl":"pkg:github/kigster/bashmatic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kigster%2Fbashmatic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kigster%2Fbashmatic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kigster%2Fbashmatic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kigster%2Fbashmatic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kigster","download_url":"https://codeload.github.com/kigster/bashmatic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kigster%2Fbashmatic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278866936,"owners_count":26059671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ascii-graphics","automation","bash","functions","helpers","installation","library","scripting","ui","ui-components"],"created_at":"2024-08-01T09:00:56.148Z","updated_at":"2025-10-07T23:56:46.302Z","avatar_url":"https://github.com/kigster.png","language":"Shell","readme":"[separator=—]\n= Bashmatic® — BASH-based DSL helpers for humans, sysadmins, and fun.\n// vim: ft=asciidoc\n:author: Version v3.5.0\n:doctype: book\n:source-highlighter: rouge\n:rouge-style: base16.monokai\n:toclevels: 5\n:toc:\n:sectnums: 9\n:icons: font\n:license: MIT\n\n\n== CI Matrix\n\n.CI Matrix\n[width=\"80%\",cols=\"\u003e.^s,\u003c.^m,^.^s\",frame=\"topbot\",options=\"header,footer\"]\n|==========================\n|                    | Badges  |  FOSSA Scanning\n| FOSSSA             | image:https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkigster%2Fbashmatic.svg?type=shield[License Status,link=https://app.fossa.com/projects/git%2Bgithub.com%2Fkigster%2Fbashmatic?ref=badge_shield] .7+\u003c.\u003e| image:https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkigster%2Fbashmatic.svg?type=large[FOSSA License Scan,link=https://app.fossa.com/projects/git%2Bgithub.com%2Fkigster%2Fbashmatic?ref=badge_large]\n| CI Tests           | image:https://github.com/kigster/bashmatic/actions/workflows/tests.yml/badge.svg[Test,link=https://github.com/kigster/bashmatic/actions/workflows/tests.yml]\n| CI Install         | image:https://github.com/kigster/bashmatic/actions/workflows/install.yml/badge.svg[Install,link=https://github.com/kigster/bashmatic/actions/workflows/install.yml]\n| ShellCheck         | image:https://github.com/kigster/bashmatic/actions/workflows/lint.yml/badge.svg[Lint,link=https://github.com/kigster/bashmatic/actions/workflows/lint.yml]\n| Gitter             | image:https://badges.gitter.im/kigster/bashmatic.svg[link=\"https://gitter.im/kigster/bashmatic?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge\"]\n|==========================\n\n== Introduction \n\n_Bashmatic®_ is a BASH framework, meaning it's a collection of BASH functions (almost 900 of them) that, we hope, make BASH programming **easier, more enjoyable, and more importantly, fun** - due to the library's focus on providing the developer with a constant feedback about what is happening, while a script that uses Bashmatic's helpers is running.\n\n== Please Donate \n\nhttps://liberapay.com/kigster/donate[image:https://liberapay.com/assets/widgets/donate.svg[Donate using Liberapay,height=30]]   https://liberapay.com/kigster/donate[image:https://img.shields.io/liberapay/goal/kigster.svg?logo=liberapay[https://img.shields.io/liberapay/goal/kigster,height=30]]\n\n\n[TIP]\n====\nWe suggest that you learn about Bashmatic from the **https://github.com/kigster/bashmatic/blob/main/README.pdf[PDF version of this document]** which is much better for print.\n\n* We recently began providing function documentation using a fork of `shdoc` utility. You can find the auto-generated documentation in the https://github.com/kigster/bashmatic/blob/main/doc/USAGE.md[USAGE] file, or its https://github.com/kigster/bashmatic/blob/main/doc/USAGE.pdf[PDF] version.\n\n* There is also an auto-generated file listing the source of every function and module. You can find it https://github.com/kigster/bashmatic/blob/main/doc/FUNCTIONS.adoc[FUNCTIONS].\n\n* Additionally please checkout the https://github.com/kigster/bashmatic/blob/main/doc/CHANGELOG.md[CHANGELOG] and the https://github.com/kigster/bashmatic/blob/main/doc/LICENSE.adoc[LICENSE].\n====\n\n====\nAfter you install the library (the default location is `~/.bashmatic`), realize that you have a choice of either:\n\n* Automatically *sourcing the library (and all 900+ functions) from your shell 'dotfiles'* like `~/.bash_profile` by adding this line: `source ~/.bashmatic/init.sh`. On a recent M1 Apple laptop this adds about 100ms total.\n* OR, can *skip it during your login initialization*, and only load it at the top of the scripts that use the library.\n====\n\n[CAUTION]\nBoth approaches are absolutely valid and have their pros and cons. Loading bashmatic in your dotfiles could be a bit risky. One way or another we'll soon provide ways to verify that bashmatic you download is the safe and correct version, every time.\n\n\nAll we'll say on this matter is that we manage the optimize the hell out of the sourcing the library. Here is an example:\n\nimage::doc/img/bashmatic-init.png[Init,width=85%,align=center,border=5,margin=10]\n\n== Programming Style: Modern BASH + DSL\n\n_Bashmatic®_'s programming style is heavily influenced by Ruby's DSL languages. If you take a quick look at the https://github.com/kigster/bashmatic/blob/main/lib/is.sh[is.sh] script, it defines a bunch of DSL functions that can be chained with `\u0026\u0026`  and `||` to create a compact and self-documenting code like this:\n\nicon:arrow-circle-down[3x, color=\"purple\"]\n\n[source,bash]\n----\n# An example of a DSL-like function \nfunction bashmatic.auto-update() {\n  local dir=\"${1:-\"${BASHMATIC_HOME\"}}\"\n  is.a-directory \"${dir}\" \u0026\u0026 {\n    file.exists-and-newer-than \"${dir}/.last-update\" 30 \u0026\u0026 return 0\n    ( \n      cd ${BASHMATIC_HOME} \u0026\u0026 \\\n      git.is-it-time-to-update \u0026\u0026 \\\n      git.sync-remote \n    )\n  }\n}\n\n# check if the function is defined and call it \nis.a-function.invoke bashmatic.auto-update \"$@\"\n----\n\nTo use it in your own scripts, you'll want to first study the Examples provided below, and take advantage of ach module available under `lib`.\n\nFinal note, - once Bashmatic is installed and loaded by your shell init files, you can type `is.\u003ctab\u003e\u003ctab\u003e` to see what functions are available to you that start with `is`. Each module under `lib` typically defines public functions starting with the name of the file. Such as, functions in `array.sh` typically start with `array.\u003csomething\u003e.\u003caction\u003e`\n\n_Bashmatic®_ offers a huge range of ever-growing helper functions for running commands, auto-retrying, repeatable, runtime-measuring execution framework with the key function `run`. There are helpers for every occasion, from drawing boxes, lines, headers, to showing progress bars, getting user input, installing packages, and much more.\n\nNOTE: A good portion of the helpers within *_Bashmatic®_ are written for OS-X, although many useful functions will also work under linux.*  Our entire  test suite runs on Ubuntu. There is an effort underway to convert Homebrew-specific functions to OS-neutral helpers such as `package.install` that would work equally well on linux.\n\nStart exploring _Bashmatic®_ below with our examples section. When you are ready, the complete entire set of pubic functions (nearly 500 of those) can be found in the https://github.com/kigster/bashmatic/blob/main/doc/FUNCTIONS.adoc[functions index page].\n\nAnd, finally, don't worry, *_Bashmatic®_* is totally open source and free to use and extend. We just like the way it looks with a little *®* :) \n\n\n== Compatibility\n\n* BASH version 4+\n* BASH version 3 (partial compatibility, some functions are disabled)\n* ZSH – as of recent update, Bashmatic is almost 90% compatible with ZSH.   \n\n**Not Currently Supported**\n\n* FISH (although you could use Bashmatic via the `bin/bashmatic` script helper or its executables)\n\n== Project Motivation\n\nThis project was born out of a simple realization made by several very senior and highly experienced engineers, that:\n\n* It is often easier to use BASH for writing things like universal *installers*, a.k.a. *setup scripts*, *uploaders*, wrappers for all sorts of functionality, such as *NPM*, *rbenv*, installing gems, rubies, using AWS, deploying code, etc.\n\n* BASH function's return values lend themselves nicely to a compact DSL (https://en.wikipedia.org/wiki/Domain-specific_language[domain specific language]) where multiple functions can be chained by logical AND `\u0026\u0026` and OR `||` to provide a very compact execution logic. Most importantly, we think that this logic is *extremely easy to read and understand.*\n\nDespite the above points, it is also generally accepted that:\n\n* A lot of BASH scripts are very poorly written and hard to read and understand.\n* It's often difficult to understand what the hell is going on while the script is running, because either its not outputting anything useful, OR it's outputting way too much.\n* When BASH errors occur, shit generally hits the fan and someone decides that they should rewrite the 20-line BASH script in C{pp} or Go, because, well, it's a goddamn BASH script and it ain't working.\n\nTIP: _Bashmatic_'s goal is to make BASH programming both fun, consistent, and provide plenty of visible output to the user so that there is no mystery as to what is going on.\n\n== Installing Bashmatic\n\nPerhaps the easiest way to install _Bashmatic®_ is using `curl` as shown below. \n\nFirst, make sure that you have Curl installed, run `which curl` to see. Then copy/paste this command into your Terminal.\n\n=== 1. Automated Install\n\nicon:arrow-down[3x, color=\"yellow\"]\n\n[source,bash]\n----\nbash -c \"$(curl -fsSL https://bashmatic.re1.re); bashmatic-install -q\"\n----\n\nicon:arrow-up[3x, color=\"yellow\"]\n\nWhere: \n\n* -q stands for \"quiet\"; \n* -v for \"verbose\"\n\nTIP: The URL _https://bashmatic.re1.re_ redirects to the HEAD of the https://raw.githubusercontent.com/kigster/bashmatic/main/bin/bashmatic-install[`bin/bashmatic-install`] script in the Github Bashmatic Repo. We use this URL so that we retain the ability to redirect the installation to a different script in the future, if need be.\n\n=== 2. Automated Install, More Explicit\n\nIf you prefer to be able to examine the script before executing code piped straight off the Internet, I don't blame you. You are cautious and smart. \n\nFor folks like you, here is a slightly more secure way of doing the same thing:\n\n[source,bash]\n----\nexport script=\"/tmp/install\"\ncurl -fsSL https://bashmatic.re1.re \u003e /tmp/install\nchmod 755  /tmp/install\n\n# At this point you can examine /tmp/install\n/tmp/install --help\n/tmp/install --verbose --debug # install with extra info\n----\n\nThis method allows you to examine the `/tmp/install` script before running it.\n\nBelow are some of the explanations \n\n==== Installing a Particular Version or a Branch\n\nYou can install a branch or a tag of Bashmatic by passing `-b / --git-branch \u003ctag|branch\u003e` flag.\n\n==== Customizing the Installer Script\n\nYou can pass flags to the `bashmatic-install` function to control how, where to Bashmatic is installed, and where from it is downloaded, including:\n\n- `-v` or `--verbose` for displaying additional output, or the opposite: \n- `-d` or `--debug` will print additional debugging output \n- `-f` or `--force` will replace any existing bashmatic folder with the new one\n- `-q` or `--quiet` for no output\n- `-l` or `--skip-on-login` to NOT install the hook that loads Bashmatic on login.\n- If you prefer to install Bashmatic in a non-standard location (the default is `~/.bashmatic`),  you can use the `-H PATH` flag\n\n.Example of a customized installation\n====\nFor instance, here we are installing Bashmatic into a non-default destination, while printing additional verbose \u0026 debug information, as well as using `-f` (force) to possibly overwrite the destination folder (if it already exists) with a checkout of Bashmatic according to a tag `v2.4.1`:\n\n[source,bash]\n----\nbash -c \"$(curl -fsSL https://bashmatic.re1.re); \\\n    bashmatic-install -d -v -f -b v2.4.1 -H ~/workspace/bashmatic\"\n----\n\n====\n\nIf you have your SSH keys installed both locally, and the public key was configured with your account on Github, you might want to install Bashmatic using `git@github.com:kigster/bashmatic` origin, instead of the default `https://github.com/kigster/bashmatic`:\n\n\nHere is the complete list of options accepted by the installer:\n\nimage::doc/img/bashmatic-install.png[Installer,width=99%,align=left,border=5,margin=10]\n\n=== Understanding what the Installer Does\n\nWhen you run `bash -c \"$(curl -fsSL https://bashmatic.re1.re); bashmatic-install\"`, the following typically happens:\n\n* `curl` downloads the `bin/bashmatic-install` script and passes it to the built-in BASH for evaluation.\n* Once evaluated, function `bashmatic-install` is invoked, which actually performs the installation.\n** This is the function that accepts the above listed arguments.\n* The script may ask for your password to enable sudo access - this may be required on OS-X to install XCode Developer tools (which include `git`)\n* If your version of BASH is 3 or older, the script will download and build from sources version 5+ of BASH,  and install it into `/usr/local/bin/bash`. SUDO may be required for this step.\n* On OS-X the script will install Homebrew on OS-X, if not already there.\n** Once Brew is installed, brew packages `coreutils` and `gnu-sed` are installed, as both are required and are relied upon by Bashmatic.\n* The script will then attempt to `git clone` the bashmatic repo into the Bashmatic home folder, or - if it already exists - it will `git pull` latest changes.\n* Finally, unless you specify `-l` or `--skip-on-login` the script will check your bash dot files, and will add the hook to load Bashmatic from either `~/.bashrc` or `~/.bash_profile`.\n\nThe last part my require some explanation.\n\n==== To load Bashmatic at Login, or Not?\n\nNow, you may or may not want to load Bashmatic on login. \n\n===== If you load Bashmatic on login (the default installer mode):\n\nIn other words, you have something like this in your `~/.bashrc`:\n\n[source,bash]\n----\n# Let's see if ~/.bashrc mentions Bashmatic:\n$ grep bashmatic ~/.bashrc \n[[ -f ~/.bashmatic/init.sh ]] \u0026\u0026 source ~/.bashmatic/init.sh\n----\n\n[ATTENTION]\n====\nicon:check-circle[fw, color=\"green\"] Pros of loading at login:: Instant access to 800+ convenience functions Bashmatic© offers and helpers. Bashmatic will auto-update whenever its loaded from the main branch.\n\nicon:times-circle[fw, color=\"red\"] Cons of loading at login:: About __134ms__ delay at login, and a potential security attack vector (eg, if someone hacks the repo).\n\nTIP: We recently dramatically improved the loading time of the entirety of Bashmatic© functions. Previously it took nearly 900ms, almost a full second to load 854 functions. Today it's no more than 180ms:\n\n[source,bash]\n----\n❯ time source init.sh\n\nreal  0m0.134s\nuser  0m0.078s\nsys\t  0m0.074s\n----\n\n====\n\nIf the above command shows the output you see above, when you grep your `bashrc` or `zshrc`, then all Bashmatic Functions will be loaded into your shell. This could be very convenient, for instance, \n\n* you could invoke `ruby.install-ruby-with-readline-and-openssl 3.0.1` to get Ruby installed. \n\n* You could invoke `gem.remote.version sym` to see that the last published verison of `sym` is `3.0.1`.\n\n* You could join an array of values with with `array.join \", \" apple pear orange`\n\nNOTICE: Bashmatic takes no more than 200-300ms to load typically. That said, you might not want to have this many shell functions in your environment, so in that case you can skip login hook by passing `-l` or `--skip-on-login`.\n\n===== If you do not want to load Bashnmatic on login\n\nInstall it with:\n\n[source,bash]\n----\nbash -c \"$(curl -fsSL https://bashmatic.re1.re); bashmatic-install -l\"\n----\n\nIn this case we suggest that you simply add the Bashmatic's `bin` folder to the `$PATH`. \n\nFor instance:\n\n[source,bash]\n----\n# ~/.bashrc\nexport BASHMATIC_HOME=\"${HOME}/.bashmatic\"\nexport PATH=\"${BASHMATIC_HOME}/bin:${PATH}\"\n----\n\nThen you will have access to the executable script `bashmatic` which can be used **as a \"gateway\" to all bashmatic functions:*\n\nYou use it like so: `bashmatic \u003cfunction\u003e \u003cargs\u003e`:\n\nIMPORTANT: Examples below assume you've set the `PATH` to include `${HOME}/.bashmatic/bin`\n\n\n[source,bash]\n----\n# Eg, if as in the previous example you sourced in Bashmatic:\n$ bashmatic.version\n2.1.2\n\n# If you have not, you can still invoke 'bashmatic.version':\n$ bashmatic version\n\n# Or another function, 'array.join' — if you sourced in init.sh:\n$ array.join '|' hello goodbye\nhello|goodbye\n\n# Or using the script:\n$ bashmatic array.join '|' hello goodbye\nhello|goodbye\n\n----\n\nIf you get an error, perhaps _Bashmatic®_ did not properly install.\n\n\n=== When `curl` is not available\n\nTherefore for situawtion where `curl` may not be available, offer the following shell function that works on Linux/Ubuntu and OS-X-based systems. It can be easily extended with new operating systems:\n\n[source,bash]\n----\n# @description Installs bashmatic dependency into the ~/.bashmatic folder.\nfunction install_bashmatic() {\n  # install bashmatic using https:// URL instead of git@\n  command -v curl \u003e/dev/null || {\n    local OS=$(uname -s)\n    local code\n    case ${OS} in\n    Linux)\n      apt-get update -yq \u0026\u0026 apt-get install curl -yqq\n      code=$?\n      ((code)) \u0026\u0026 sudo apt-get update -yq \u0026\u0026 sudo apt-get install curl -yqq\n      ;;\n    Darwin)\n      command -v brew \u003e/dev/null || /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"\n      hash -r\n      brew install curl\n      ;;\n    *)\n      echo \"OS ${OS} is not supported.\"\n      ;;\n    esac\n  }\n  [[ -d ~/.bashmatic ]] || bash -c \"$(curl -fsSL https://bashmatic.re1.re); bashmatic-install -q -m https\"\n  return 0\n}\n----\n\n==== Discovering Available Functions\n\nTo discover the breadth of available functions, type the following command to see all imported shell functions:\n\n[source,bash]\n----\n# List all functions using 4-column mode; print top 5 lines.  \n❯ bashmatic functions 4 | head -5\n7z.a         db.psql.connect.db-set hl.yellow-on-gray  run.inspect-variables\n7z.install   db.psql.connect.db-set hr                 run.inspect-variables-\n7z.unzip     db.psql.connect.just-d hr.colored         run.inspect.set-skip-f\n7z.x         db.psql.connect.table- http.servers       run.on-error.ask-is-en\n7z.zip       db.psql.connect.table- https.servers      run.print-command\n\n# or, to get the count of all functions, use 1 column output:\n$ bashmatic functions 1 | wc -l\n773 \n----\n\n=== Manual Installation\n\nTo install Bashmatic manually, follow these steps (feel free to change `BASHMATIC_HOME` if you like):\n  \n\n=== Using Git\n\n[source,bash]\n----\nexport BASHMATIC_HOME=\"${HOME}/.bashmatic\"\ntest -d \"${BASHMATIC_HOME}\" || \\\n  git clone https://github.com/kigster/bashmatic.git \"${BASHMATIC_HOME}\"\ncd \"${BASHMATIC_HOME}\" \u0026\u0026 ./bin/bashmatic-install -v\ncd -\u003e/dev/null\n----\n\n=== Using Curl\n\nSometimes you may not be able to use `git` (I have seen issues ranging from local certificate mismatch to old versions of git, and more), but maybe able to download with `curl`. In that case, you can lookup the https://github.com/kigster/bashmatic/tags[latest tag] (substitute \"v1.6.0\" below with that tag), and then issue this command:\n\n[source,bash]\n----\nexport BASHMATIC_TAG=\"v2.4.1\"\nset -e\ncd ${HOME}\ncurl --insecure -fSsl \\\n  https://codeload.github.com/kigster/bashmatic/tar.gz/${BASHMATIC_TAG} \\\n  -o bashmatic.tar.gz\nrm -rf .bashmatic \u0026\u0026 tar xvzf bashmatic.tar.gz \u0026\u0026 mv bashmatic-${BASHMATIC_TAG} .bashmatic\nsource ~/.bashmatic/init.sh\ncd ${HOME}/.bashmatic \u0026\u0026 ./bin/bashmatic-install -v\ncd ~ \u003e/dev/null\n----\n\n=== Reloading Bashmatic\n\nYou can always reload _Bashmatic®_ with `bashmatic.reload` function. This simply performs the sourcing of `${BASHMATIC_HOME}/init.sh`.\n\n=== Loading Bashmatic at Startup\n\nWhen you install Bashmatic it automatically adds a hook to your `~/.bash_profile`, but if you are on ZSH you may need to add it manually (for now).\n\nAdd the following to your `~/.zshrc` file:\n\n[source,zsh]\n[[ -f ~/.bashmatic/init.sh ]] \u0026\u0026 source \"~/.bashmatic/init.sh\"\n\nNOTE: The entire library takes less than 300ms to load on ZSH and a recent MacBook Pro.\n\n== Discovering via the `Makefile`\n\nThe top-level `Makefile` is mostly provided as a convenience as it encapsulates some common tasks used in development by Bashmatic Author(s), as well as others useful to anyone exploring Bashmatic.\n\nYou can run `make help` and read the available targets:\n\n[source,bash]\n----\n❯ make\n\nhelp               Prints help message auto-generated from the comments.\nopen-readme        Open README.pdf in the system viewer\n\ndocker-build       Builds the Docker image with the tooling inside\ndocker-run-bash    Drops you into a BASH session with Bashmatic Loaded\ndocker-run-fish    Drops you into a FISH session with Bashmatic Loaded\ndocker-run-zsh     Drops you into a ZSH session with Bashmatic Loaded\ndocker-run         Drops you into a BASH session\n\nfile-stats-git     Print all  files  known to `git ls-files` command\nfile-stats-local   Print all non-test files and run `file` utility on them.\n\ninstall-dev        Installs the Development Tooling using dev-setup script\ninstall-ruby       Installs the Bashmatic default Ruby version using rbenv\ninstall            install BashMatic Locally in ~/.bashmatic\n\nrelease            Make a new release named after the latest tag\ntag                Tag this commit with .version and push to remote\n\nsetup              Run the comprehensive development setup on this machine\nshell-files        Lists every single checked in SHELL file in this repo\n\ntest               Run fully automated test suite based on Bats\ntest-parallel      Run the fully auto-g mated test suite\n\nupdate-changelog   Auto-generate the doc/CHANGELOG (requires GITHUB_TOKEN env var set)\nupdate-functions   Auto-generate doc/FUNCTIONS index at doc/FUNCTIONS.adoc/pdf\nupdate-readme      Re-generate the PDF version of the README\nupdate-usage       Auto-generate doc/USAGE documentation from lib shell files, \n                   to doc/USAGE.adoc/pdf\n\nupdate             Runs all update targets to regenerate all PDF docs and the \n                   Changelog.\n----\n\nI've added whitespaces around a set of common tasks you might find useful. \n\nLet's take a quick look at what's available here.\n\n=== Befriending the Makefile \n\nMakefile is provided as a convenience for running most common tasks and to simplify running some more complex tasks that require remembering many arguments, such as `make setup`. You might want to use the Makefile for several reasons:\n\n1. `make open-readme`\n+\nThis tasks opens the PDF version of the README in your PDF system viewer.\n\n1. `make install`\n+\nThis allows you to install the Bashmatic Framework locally. It simply runs `bin/bashmatic-install` script. At most this will add hooks to your shell init files so that Bashmatic is loaded at login.\n\n1. `make setup`\n+\nThis task invokes the `bin/dev-setup` script under the hood, so that you can setup your local computer developer setup for software development.\n+\n\n+\nNow, this script offers a very rich CLI interface, so you can either run the script directly and have a fine-grained control over what it's doing, or you can run it with default flags via this make  target.\n+\nThis particular make target runs `bin/dev-setup` script with the following actions: \n\n+\n`dev, cpp, fonts, gnu, go, java, js, load-balancing, postgres, ruby`\n\n1. `make test` and `make test-parallel`  are both meant for Bashmatic Developers and contributors. Please see the https://github.com/kigster/bashmatic#contributing[Contributing] section on how to run and what to expect from the UNIT tests.\n\n1. `make update` is the task that should be run by library contributors after they've made their their changes and want the auto-generated  documentation to reflect the  new functions added and so on and so force.  This tasks also generates the function index, re-generate the latest PDFs of `README`, `USAGE` or the `CHANGELOG` files.\n\nNOTE: Running `make update` is is required for submitting any pull request.\n\n=== Docker Make Targets\n\nBashmatic comes with a Dockerfile that can be used to run tests or just manually validate various functionality under Linux, and possibly to experiment.\n\nRun `make docker-build` to create an docker image `bashmatic:latest`.\n\nRun `make docker-run-bash` (or `...-zsh` or `...-fish`) to start a container with your favorite shell, and then validate if your functions work as expected.\n\nimage::doc/img/docker-bash.png[Docker Build,width=100%,align=center]\n\nNote how this dropped me straight into the Linux environment prompt with Bashmatic already installed.\n\n\n== Examples of Bashmatic in Action  \n\n**Why do we need another BASH framework?**\n\nBASH is know to be too verbose and unreliable. We beg to differ. This is why we wanted to start this README with a couple of examples.\n\n=== Example I. Install Gems via Homebrew \n\nJust look at this tiny, five-line script:\n\n[source,bash]\n----\n#!/usr/bin/env bash\n\nsource ${BASHMATIC_HOME}/init.sh\n\nh2 \"Installing ruby gem sym and brew package curl...\" \\\n   \"Please standby...\"\n\ngem.install \"sym\" \u0026\u0026 brew.install.package \"curl\" \u0026\u0026 \\\n  success \"installed sym ruby gem, version $(gem.version sym)\"\n----\n\nResults in this detailed and, let's be honest, _gorgeous_ ASCII output:\n\nimage::doc/img/bashmatic-example.png[example,width=100%,border=2]\n\nTell me you are not at all excited to start writing complex installation flows in BASH right away?\n\nNot only you get pretty output, but you can each executed command, it's exit status, whether it's been successful (green/red), as well each command's bloody duration in milliseconds. What's not to like?!?\n\nStill not convinced?\n\nTake a look at a more comprehensive example next.\n\n=== Example II: Download and install binaries.\n\nIn this example, we'll download and install binaries `kubectl` and `minikube` binaries into `/usr/local/bin`\n\nWe provided an example script in link:examples/k8s-installer.sh[`examples/k8s-installer.sh`]. Please click and take a look at the source.\n\nHere is the output of running this script:\n\nimage::doc/img/k8installer.png[K8 Minicube Installer,width=100%,align=center]\n\nWhy do we think this type of installer is pretty awesome, compared to a silent but deadly shell script that \"Jim-in-the-corner\" wrote and now nobody understands?\n\nBecause:\n\n. The script goes out of its way to over-communicate what it does to the user.\n. It allows and reminds about a clean getaway (Ctrl-C)\n. It shares the exact command it runs and its timings so that you can eyeball issues like network congestions or network addresses, etc.\n. It shows in green exit code '0' of each command. Should any of the commands fail, you'll see it in red.\n. Its source code is terse, explicit, and easy to read. There is no magic. Just BASH functions.\n\nNOTE: If you need to create a BASH installer, _Bashmatic®_ offers some incredible time savers.\n\nLet's get back to the Earth, and talk about how to install Bashmatic, and how to use it in more detail right after.\n\n\n=== Example III: Developer Environment Bootstrap Script\n\nThis final and most feature-rich example is not just an example – **it's a working functioning tool that can be used to install a bunch of developer dependencies on your Apple Laptop**.\n\nNOTE: the script relies on Homebrew behind the scenes, and therefore would not work on Linux or Windows (unless Brew gets ported there).\n\nIt's located in https://github.com/kigster/bashmatic/blob/main/bin/dev-setup[`bin/dev-setup`] and has many CLI flags:\n\nimage::doc/img/dev-setup.png[Developer Setup,width=100%,align=center]\n\nIn the example below we'll use `dev-setup` script to install the following:\n \n* Dev Tools\n* PostgreSQL \n* Redis\n* Memcached \n* Ruby 2.7.1\n* NodeJS/NPM/Yarn\n\nDespite that this is a long list, we can install it all in one command.\n\nWe'll run this from a folder where our application is installed, because then the Ruby Version will be auto-detected from our `.ruby-version` file, and in addition to installing all the dependencies the script will also run `bundle install` and `npm install` (or `yarn install`). Not bad, huh?\n\n[source,bash]\n----\n${BASHMATIC_HOME}/bin/dev-setup \\\n  -g \"ruby postgres mysql caching js monitoring\" \\\n  -r $(cat .ruby-version) \\\n  -p 9.5 \\ # use PostgreSQL version 9.5\n  -m 5.6   # use MySQL version 5.6\n----\n\nThis compact command line installs a ton of things, but don't take our word for it - run it yourself. Or, at the very least enjoy this https://github.com/kigster/bashmatic/blob/main/.dev-setup-completed.png[one extremely long screenshot] :)\n\n\n=== Example IV: Installing GRC Colourify Tool\n\nThis is a great tool that colorizes nearly any other tool''s output.\n\nRun it like so:\n\n[source,bash]\n${BASHMATIC_HOME}/bin/install-grc\n\nYou might need to enter your password for SUDO.\n\nOnce it completes, run `source ~/.bashrc` (or whatever shell you use), and type something like `ls -al` or `netstat -rn` or `ping 1.1.1.1` and notice how all of the above is nicely colored.\n\n\n=== Example V: `db` Shortcut for Database Utilities \u0026 `db top`\n\nIf you are using PostgreSQL, you are in luck! Bashmatic includes numerous helpers for PostreSQL's CLI\nutility `psql`.\n\nNOTE: Before you begin, we recommend that you install file `.psqlrc` from Bashmatic's `conf` directory into your home folder. While not required, this file sets up your prompt and various macros for PostgreSQL that will come very handy if you use `psql` with any regularity.\n\nWhat is `db top` anyway?\n\nJust like with the regular `top` you can see the \"top\" resource-consuming processes running on your local system, with `dbtop` you can observe a self-refreshing report of the actively running queries on up to *three database servers* at the same time.\n\nHere is the pixelated screenshot of `dbtop` running against two live databases:\n\nimage::doc/img/dbtop.png[DBTop Example,width=100%,align=center,link=\"https://github.com/kigster/bashmatic/blob/main/FUNCTIONS.adoc#db-top\"]\n\nIn order for this to work, you must first define database connection parameters in a YAML file located at the following PATH: `~/.db/database.yml`.\n\nHere is how the file should be organized (if you ever used Ruby on Rails, the standard `config/database.yml` file should be fully compatible):\n\n[source,yaml]\n----\ndevelopment:\n  database: development\n  username: postgres\n  host: localhost\n  password: \nstaging:\n  database: staging\n  username: postgres\n  host: staging.db.example.com\n  password: \nproduction:\n  database: production\n  username: postgres\n  host: production.db.example.com\n  password: \"a098098safdaf0998ff79789a798a7sdf\"\n----\n\nGiven the above file, you should be able to run the following command to see all available (registered in the above YAML file) connections:\n\n[source,bash]\n----\n$ db connections\ndevelopment\nstaging\nproduction\n----\n\nOnce that's working, you should be able run `dbtop`:\n\n[source,bash]\n----\ndb top development staging production\n----\n\nNOTE: At the moment, only the default port 5432 is supported. If you are using an alternative port, and as long as it's shared across the connections you can set the `PGPORT` environment variable that `psql` will read.\n\n**DB Top Configuration**:\n\nYou can configure the following settings for `db top`:\n\n1. You can change the location of the `database.yml` file with `db.config.set-file \u003cfilepath\u003e`\n2. You can change the refresh rate of the `dbtop` with eg. `db.top.set-refresh 0.5` (in seconds, fractional values allowed). This sets the sleep time between the screen is fully refreshed.\n\n=== Other `db` Functions\n\nIf you run `db` without any arguments, or with `-h` you will see the following:\n\nimage::doc/img/db.png[db usage,border=2,width=100%,align=center]\n\nAs you might notice, there is an ever-growing list of \"actions\" — the sub-commands to the `db` script.\n\n=== Sub-Commands of `db` \n\nYou can view the full list by passing `--commands` flag:\n\nimage::doc/img/db-commands.png[db usage,border=2,width=100%,align=center]\n\nAltgernatively, here is the `--examples` view:\n\nimage::doc/img/db-examples.png[db examples,border=2,width=100%,align=center]\n\n==== Sub-Command `db connections`\n\nYou can get a list of all availabled db connections with either\n\n[source,bash]\n----\ndb connections\n# OR \ndb --connections\n----\n\nimage::doc/img/db-connections.png[db usage,border=2,width=100%,align=center]\n\n==== Sub-Command `db pga` (eg. `pg_activity`)\n\nFor instance, a recent addition is the ability to invoke https://github.com/dalibo/pg_activity[pg_activity] Python-based DB \"top\", a much more advanced top query monitor for PostgreSQL.\n\nYou can invoke `db pga \u003cconnection\u003e` where the connection is taken from the database connection definitions shown above. This is what `pg-activity` looks like in action:\n\nimage::doc/img/db-pga.png[pg_activity,border=2,width=100%,align=center]\n\n==== Other Sub-Commands\n\nOnce you know what database you are connecting to, you can then run one of the commands: \n\ndb connect \u003cconnection\u003e::\nopens psql session to the given connection\n\ndb db-settings-toml \u003cconnection\u003e::\nprints all PostgreSQL settings (obtained with `show all`) as a sorted TOML-formatted file.\n\ndb -q list-tables \u003cconnection\u003e::\nprint a  list of all tables in the given database, -q (or --quiet) skips  printing the header so that only the table listing is printed.\n\ndb csv \u003cconnection\u003e \u003cquery\u003e::\nexport the result of the query as a CSV to STDOUT, eg \n\n[source,bash]\n----\n$ db csv filestore \"select * from files limit 2\"\n----\n\nResults in the following output\n\n[source,CSV]\n----\ncomponent_id,file_path,fingerprint_sha_256,fingerprint_comment_stripped_sha_256,license_info\n6121f5b3-d68d-479d-9b83-77e9ca07dd2b,weiboSDK/src/main/java/com/sina/weibo/sdk/openapi/models/Tag.java,\n6121f5b3-d68d-479d-9b83-77e9ca07dd2b,weiboSDK/src/main/java/com/sina/weibo/sdk/openapi/models/Comment.java,\n----\n\n=== `bin/tablet` Script \n\nBuilding atop of the powerful `db` script mechanics, is another powerful script called `tablet`.\n\nThe script is meant to be run against one database, and perform a table-level operation on a set of tables that can be specified in numerous ways. It started with the need to ANALYZE only some of the tables, specifically those that have not been auto-analyzed, but grew into a much more capable tool that can do things like:\n\n * Analyze all tables in a database that have never been analyzed`\n * Analyze all tables in a database that have not been analyzed in N days\n * Analyze a set of specific tables, or exclude tables using regular expression\n * Instead of analyzing tables, perform any other table-level command such as:\n ** `TRUNCATE`\n ** `VACUUM` and `VACCUUM FULL`\n ** `DROP TABLE`\n ** `REINDEX TABLE`\n ** etc..\n\nBelow is the screenshot of the help screen from this script:\n\nimage::doc/img/bashmatic-tablet.png[Tablet Script in Action,border=2,width=100%,align=center]\n\n== Usage\n\nWelcome to *Bashmatic* – an ever growing collection of scripts and mini-bash frameworks for doing all sorts of things quickly and efficiently.\n\nWe have adopted the https://google.github.io/styleguide/shell.xml[Google Bash Style Guide], and it's recommended that anyone committing to this repo reads the guides to understand the conventions, gotchas and anti-patterns.\n\n=== Function Naming Convention Unpacked\n\n_Bashmatic®_ provides a large number of functions, which are all loaded in your current shell. The functions are split into two fundamental groups:\n\n* Functions with names beginning with a `.` are considered \"private\" functions, for example `.run.env` and `.run.initializer`\n* All other functions are considered public.\n\nThe following conventions apply to all functions:\n\n* We use the \"dot\" for separating namespaces, hence `git.sync` and `gem.install`.\n* Function names should be self-explanatory and easy to read.\n* DO NOT abbreviate words.\n* All public functions must be written defensively: i.e., if the function is called from the Terminal without any arguments, and it requires arguments, the function _must print its usage info_ and a meaningful error message.\n\nFor instance:\n\n[source,bash]\n----\n$ gem.install\n┌─────────────────────────────────────────────────────────┐\n│  « ERROR »  Error - gem name is required as an argument │\n└─────────────────────────────────────────────────────────┘\n----\n\nNow let's run it properly:\n\n[source,bash]\n----\n$ gem.install simple-feed\n       installing simple-feed (latest)...\n  ✔︎    $ gem install simple-feed   ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪〔   5685 ms 〕    0\n  ✔︎    $ gem list \u003e ${BASHMATIC_TEMP}/.gem/gem.list ▪▪▪▪▪▪〔    503 ms 〕    0\n----\n\nThe naming convention we use is a derivative of Google's Bash StyleGuide, using `.` to separate BASH function namespaces instead of much more verbose `::`.\n\n=== Seeing All Functions\n\nAfter running the above, run `bashmatic.functions` function to see all available functions. You can also open the xref:doc/FUNCTIONS.adoc[FUNCTIONS.adoc] file to see the alphabetized list of all 422 functions.\n\n=== Seeing Specific Functions\n\nTo get a list of module or pattern-specific functions installed by the framework, run the following:\n\n[source,bash]\n----\n$ bashmatic.functions-from pattern [ columns ]\n----\n\nFor instance:\n\n[source,bash]\n----\n$ bashmatic.functions-from docker 2\ndocker.abort-if-down                    docker.build.container\ndocker.actions.build                    docker.containers.clean\n.......\ndocker.actions.update\n----\n\n=== Various Modules\n\nYou can list various modules by listing the `lib` sub-directory of the `${BASHMATIC_HOME}` folder.\n\nNote how we use _Bashmatic®_ helper `columnize [ columns ]` to display a long list in five columns.\n\n[source,bash]\n----\n$ ls -1 ${BASHMATIC_HOME}/lib | sed 's/\\.sh//g' | columnize 5\n7z                deploy            jemalloc          runtime-config    time\narray             dir               json              runtime           trap\naudio             docker            net               set               url\naws               file              osx               set               user\nbashmatic         ftrace            output            settings          util\nbrew              gem               pids              shell-set         vim\ncaller            git-recurse-updat progress-bar      ssh               yaml\ncolor             git               ruby              subshell\ndb                sedx              run               sym\n----\n\n=== Key Modules Explained\n\nAt a high level, the following modules are provided, in order of importance:\n\n==== Runtime Framework — Executing Commands The Right Way™\n\nOne of the key parts of Bashmatic is the framework around running commands and reporting on their execution status. \n\nThe two most important functions in this framework are:\n\n* `run.set-next [ option option ... ]`\n* `run.set-all [ option option ... ]`\n* `run \"command\"`\n\nThe first two allow you to configure how the `run` command behaves. The `run.set-next` only affects the first invocation of `run`. After that all runtime options revert to the defaults.\n\n`run.set-all` affects ALL `run` invocations following it. \n\n[Runtime Options]\n====\nThe following options can be passed to the `run.set-next` and `run.set-all`:\n\nabort-on-error:: exits the script when the command fails. \nask-on-error:: interactively asks the user when the command fails. \ncontinue-on-error:: prints a warning, and continues when the command fails. \n***\ndry-run-on:: turns dry-run on\ndry-run-off:: turns dry-run off \n***\non-decline-exit:: when `run.ui.ask` is used and user says NO, exits the program.\non-decline-return:: when `run.ui.ask` is used and user says NO, returns from the function.\n***\nshow-command-on:: shows the command being executed\nshow-command-off:: silently executes the command\n***\nshow-output-off:: swallows command's STDOUT, but prints STDERR on error\nshow-output-on:: prints STDOUT of the command as it executes\n====\n\nFor example:\n\n```\n❯ run.set-next show-output-off; run \"ls -1 | wc -l\";  run.set-next show-output-on; run \"ls -1 | wc -l\";\n  ✔︎   ❯ ls -1 | wc -l ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪〔     74 ms 〕    0\n       # Command below will be shown with its output:\n       ❯ ls -1 | wc -l\n      17\n\n  ✔︎  ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪〔     80 ms 〕    0\n```\n\nThe following files provide this functionality:\n\n* `lib/run.sh`\n* `lib/runtime.sh`\n* `lib/runtime-config.sh`.\n\nThese collectively offer the following functions:\n\n[source,bash]\n----\n$ bashmatic.functions-from 'run*'\n\nrun                                  run.set-next\nrun.config.detail-is-enabled         run.set-next.list\nrun.config.verbose-is-enabled        run.ui.ask\nrun.inspect                          run.ui.ask-user-value\nrun.inspect-variable                 run.ui.get-user-value\nrun.inspect-variables                run.ui.press-any-key\nrun.inspect-variables-that-are       run.ui.retry-command\nrun.inspect.set-skip-false-or-blank  run.variables-ending-with\nrun.on-error.ask-is-enabled          run.variables-starting-with\nrun.print-variable                   run.with.minimum-duration\nrun.print-variables                  run.with.ruby-bundle\nrun.set-all                          run.with.ruby-bundle-and-output\nrun.set-all.list\n----\n\nUsing these functions you can write powerful shell scripts that display each command they run, its status, duration, and can abort on various conditions. You can ask the user to confirm, and you can show a user message and wait for any key pressed to continue.\n\n===== Examples of Runtime Framework\n____\nNOTE, in the following examples we assume you installed the library into your project's folder as `.bashmatic` (a \"hidden\" folder starting with a dot).\n____\n\nProgramming style used in this project lends itself nicely to using a DSL-like approach to shell programming.  For example, in order to configure the behavior of the run-time framework (see below) you would run the following command:\n\n[source,bash]\n----\n#!/usr/bin/env bash\n\n# (See below on the location of .bashmatic and ways to install it)\nsource ${BASHMATIC_HOME}/init.sh\n\n# configure global behavior of all run() invocations\nrun.set-all abort-on-error show-output-off\n\nrun \"git clone https://gthub.com/user/rails-repo rails\"\nrun \"cd rails\"\nrun \"bundle check || bundle install\"\n\n# the following configuration only applies to the next invocation of `run()`\n# and then resets back to `off`\nrun.set-next show-output-on\nrun \"bundle exec rspec\"\n----\n\nAnd most importantly, you can use our fancy UI drawing routines to communicate with the user, which are based on familiar HTML constructs, such as `h1`, `h2`, `hr`, etc.\n\n==== Controlling Output\n\nA large chunk of Bashmatic is devoted to printing pretty dialogs and controlling the output of program execution.\n\nThe `lib/output.sh` module does all of the heavy lifting with providing many UI elements, such as frames, boxes, lines, headers, and many more.\n\nHere is the list of functions in this module:\n\n[source,bash]\n----\n$ bashmatic.functions-from output 3\nabort                 error:               left-prefix\nascii-clean           h.black              ok\nbox.blue-in-green     h.blue               okay\nbox.blue-in-yellow    h.green              output.color.off\nbox.green-in-cyan     h.red                output.color.on\nbox.green-in-green    h.yellow             output.is-pipe\nbox.green-in-magenta  h1                   output.is-redirect\nbox.green-in-yellow   h1.blue              output.is-ssh\nbox.magenta-in-blue   h1.green             output.is-terminal\nbox.magenta-in-green  h1.purple            output.is-tty\nbox.red-in-magenta    h1.red               puts\nbox.red-in-red        h1.yellow            reset-color\nbox.red-in-yellow     h2                   reset-color:\nbox.yellow-in-blue    h2.green             screen-width\nbox.yellow-in-red     h3                   screen.height\nbox.yellow-in-yellow  hdr                  screen.width\nbr                    hl.blue              shutdown\ncenter                hl.desc              stderr\ncolumnize             hl.green             stdout\ncommand-spacer        hl.orange            success\ncursor.at.x           hl.subtle            test-group\ncursor.at.y           hl.white-on-orange   ui.closer.kind-of-ok\ncursor.down           hl.white-on-salmon   ui.closer.kind-of-ok:\ncursor.left           hl.yellow            ui.closer.not-ok\ncursor.rewind         hl.yellow-on-gray    ui.closer.not-ok:\ncursor.right          hr                   ui.closer.ok:\ncursor.up             hr.colored           warn\ndebug                 inf                  warning\nduration              info                 warning:\nerr                   info:\nerror                 left\n----\n\nNote that some function names end with `:` – this indicates that the function outputs a new-line in the end. These functions typically exist together with their non-`:`-terminated counter-parts.  If you use one, eg, `inf`, you are then supposed to finish the line by providing an additional output call, most commonly it will be one of `ok:`, `ui.closer.not-ok:` and `ui.closer.kind-of-ok:`.\n\nHere is an example:\n\n[source,bash]\n----\nfunction valid-cask()  { sleep 1; return 0; }\nfunction verify-cask() {\n  inf \"verifying brew cask ${1}....\"\n  if valid-cask ${1}; then\n    ok:\n  else\n    not-ok:\n  fi\n}\n----\n\nWhen you run this, you should see something like this:\n\n[source,bash]\n----\n $ verify-cask TextMate\n   ✔︎  verifying brew cask TextMate....\n----\n\nIn the above example, you see the checkbox appear to the left of the text. In fact, it appears a second after, right as `sleep 1` returns. This is because this paradigm is meant for wrapping constructs that might succeed or fail.\n\nIf we change the `valid-cask` function to return a failure:\n\n[source,bash]\n----\nfunction valid-cask()  { sleep 1; return 1; }\n----\n\nThen this is what we'd see:\n\n[source,bash]\n----\n$ verify-cask TextMate\n  ✘    verifying brew cask TextMate....\n----\n\n===== Output Components\n\nComponents are BASH functions that draw something concrete on the screen. For instance, all functions starting with `box.` are components, as are `h1`, `h2`, `hr`, `br` and more.\n\n[source,bash]\n----\n$ h1 Hello\n\n┌───────────────────┐\n│ Hello             │\n└───────────────────┘\n----\n\nThese are often named after HTML elements, such as `hr`, `h1`, `h2`, etc.\n\n===== Output Helpers\n\nHere is another example where we are deciding whether to print something based on whether the output is a proper terminal (and not a pipe or redirect):\n\n----\noutput.is-tty \u0026\u0026 h1 \"Yay For Terminals!\"\noutput.has-stdin \u0026\u0026 echo \"We are being piped into...\"\n----\n\nThe above reads more like a high level language like Ruby or Python than Shell. That's because BASH is more powerful than most people think.\n\nThere is an link:examples/test-ui.sh[example script] that demonstrates the capabilities of Bashmatic.\n\nIf you ran the script, you should see the output shown link:.bashmatic.png[in this screenshot]. Your colors may vary depending on what color scheme and font you use for your terminal.\n\n\n\n==== Package management: Brew and RubyGems\n\nYou can reliably install ruby gems or brew packages with the following syntax:\n\n[source,bash]\n----\n#!/usr/bin/env bash\n\nsource ${BASHMATIC_HOME}/init.sh\nh2 \"Installing ruby gem sym and brew package curl...\"\ngem.install sym\nbrew.install.package curl\n\nsuccess \"installed Sym version $(gem.version sym)\"\n----\n\nWhen you run the above script, you shyould seee the following output:\n\nimage::doc/img/bashmatic-example.png[example,align=center,width=100%]\n\n==== Shortening URLs and Github Access\n\nYou can shorten URLs on the command line using Bitly, but for this to work, you must set the following environment variables in your shell init:\n\n[source,bash]\n----\nexport BITLY_LOGIN=\"\u003cyour login\u003e\"\nexport BITLY_API_KEY=\"\u003cyour api key\u003e\"\n----\n\nThen you can run it like so:\n\n[source,bash]\n----\n$ url.shorten https://raw.githubusercontent.com/kigster/bashmatic/main/bin/install\n# http://bit.ly/2IIPNE1\n----\n\n==== Github Access\n\nThere are a couple of Github-specific helpers:\n\n[source,bash]\n----\ngithub.clone                  github.setup\ngithub.org                    github.validate\n----\n\nFor instance:\n\n[source,bash]\n----\n$ github.clone sym\n\n  ✘    Validating Github Configuration...\n\n       Please enter the name of your Github Organization:\n       $ kigster\n\n  Your github organization was saved in your ~/.gitconfig file.\n  To change it in the future, run: \n\n       $ github.org \u003corg-name\u003e\n\n  ✔︎ $ git clone git@github.com:kigster/sym ▪▪▪▪▪▪〔     931 ms 〕\n----\n\n==== File Helpers\n\n[source,bash]\n----\n$ bashmatic.functions-from file\n\nfile.exists_and_newer_than     file.list.filter-non-empty\nfile.gsub                      file.size\nfile.install-with-backup       file.size.mb\nfile.last-modified-date        file.source-if-exists\nfile.last-modified-year        file.stat\nfile.list.filter-existing\n----\n\nFor instance, `file.stat` offers access to the `fstat()` C-function:\n\n[source,bash]\n----\n $ file.stat README.md st_size\n22799\n----\n\n==== Array Helpers\n\n[source,bash]\n----\n$ bashmatic.functions-from array\n\narray.to.bullet-list         array.includes\narray.has-element            array.includes-or-exit\narray.to.csv                 array.from.stdin\narray-join                   array.join\narray-piped                  array.to.piped-list\narray.includes-or-complain\n----\n\nFor instance:\n\n[source,bash]\n----\n$ declare -a farm_animals=(chicken duck rooster pig)\n$ array.to.bullet-list ${farm_animals[@]}\n • chicken\n • duck\n • rooster\n • pig\n$ array.includes \"duck\" \"${farm_animals[@]}\" \u0026\u0026 echo Yes || echo No\nYes\n$ array.includes  \"cow\" \"${farm_animals[@]}\" \u0026\u0026 echo Yes || echo No\nNo\n----\n\n==== Utilities\n\nThe utilities module has the following functions:\n\n[source,bash]\n----\n$ bashmatic.functions-from util\n\npause.long                     util.install-direnv\npause                          util.is-a-function\npause.short                    util.is-numeric\npause.medium                   util.is-variable-defined\nutil.append-to-init-files      util.lines-in-folder\nutil.arch                      util.remove-from-init-files\nutil.call-if-function          util.shell-init-files\nshasum.sha-only                util.shell-name\nshasum.sha-only-stdin          util.ver-to-i\nutil.functions-starting-with   util.whats-installed\nutil.generate-password         watch.ls-al\n----\n\nFor example, version helpers can be very handy in automated version detection, sorting and identifying the latest or the oldest versions:\n\n[source,bash]\n----\n$ util.ver-to-i '12.4.9'\n112004009\n$ util.i-to-ver $(util.ver-to-i '12.4.9')\n12.4.9\n----\n\n==== Ruby and Ruby Gems\n\nlink:lib/ruby.sh[Ruby Version Helpers] and link:lib/gem.sh[Ruby Gem Helpers], that can extract curren gem version from either `Gemfile.lock` or globally installed gem list.\n\nAdditional Ruby helpers abound:\n\n[source,bash]\n----\n$ bashmatic.functions-from ruby\n\nbundle.gems-with-c-extensions  ruby.install-ruby-with-deps\ninterrupted                    ruby.install-upgrade-bundler\nruby.bundler-version           ruby.installed-gems\nruby.compiled-with             ruby.kigs-gems\nruby.default-gems              ruby.linked-libs\nruby.full-version              ruby.numeric-version\nruby.gemfile-lock-version      ruby.rbenv\nruby.gems                      ruby.rubygems-update\nruby.gems.install              ruby.stop\nruby.gems.uninstall            ruby.top-versions\nruby.init                      ruby.top-versions-as-yaml\nruby.install                   ruby.validate-version\nruby.install-ruby\n----\n\nFrom the obvious `ruby.install-ruby \u003cversion\u003e` to incredibly useful `ruby.top-versions \u003cplatform\u003e` – which, using rbenv and ruby_build plugin, returns the most recent minor version of each major version upgrade, as well as the YAML version that allows you to pipe the output into your `.travis.yml` to test against each major version of Ruby, locked to the very latest update in each.\n\n[source,bash]\n----\n$ ruby.top-versions\n2.0.0-p648\n2.1.10\n2.2.10\n2.3.8\n2.4.9\n2.5.7\n2.6.5\n2.7.0\n2.8.0-dev\n\n$ ruby.top-versions jruby\njruby-1.5.6\njruby-1.6.8\njruby-1.7.27\njruby-9.0.5.0\njruby-9.1.17.0\njruby-9.2.10.0\n\n$ ruby.top-versions mruby\nmruby-dev\nmruby-1.0.0\nmruby-1.1.0\nmruby-1.2.0\nmruby-1.3.0\nmruby-1.4.1\nmruby-2.0.1\nmruby-2.1.0\n----\n\n===== Gem Helpers\n\nThese are fun helpers to assist in scripting gem management.\n\n[source,bash]\n----\n$ bashmatic.functions-from gem\n\ng-i                                           gem.gemfile.version\ng-u                                           gem.global.latest-version\ngem.cache-installed                           gem.global.versions\ngem.cache-refresh                             gem.install\ngem.clear-cache                               gem.is-installed\ngem.configure-cache                           gem.uninstall\ngem.ensure-gem-version                        gem.version\n----\n\nFor instance\n\n[source,bash]\n----\n$ g-i awesome_print\n  ✔︎    gem awesome_print (1.8.0) is already installed\n$ gem.version awesome_print\n1.8.0\n----\n\n==== Audio \u0026 Video Compression Helpers\n\nYou can discover the audio and video functions using `bashmatic.functions` helper:\n\n[source,bash]\n----\n ❯ bashmatic.functions 1 | egrep -i 'video|audio'\naudio.dir.mp3-to-wav\naudio.dir.rename-karaoke-wavs\naudio.dir.rename-wavs\naudio.file.frequency\naudio.file.mp3-to-wav\naudio.make.mp3\naudio.make.mp3.usage\naudio.make.mp3s\nvideo-squeeze\nvideo.convert.compress\n----\n\nThese commands auto-install ffmpeg and other utilities, and then use best in class compression. For instance, here is 80% compressed video file:\n\nimage::doc/img/video-squeeze.png[Video Squeeze, width=\"100%\",align=\"center\"]\n\n==== Additional Helpers\n\nThere are plenty more modules, that help with:\n\n* link:lib/aws.sh[AWS helpers] – requires `awscli` and credentials setup, and offers some helpers to simplify AWS management.\n* link:lib/docker.sh[Docker Helpers] – assist with docker image building and pushing/pulling\n* link:lib/sym.sh[Sym] – encryption with the gem called https://github.com/kigster/sym[`sym`]\n\nAnd many more.\n\nSee the full function index with the function implementation body in the xref:doc/FUNCTIONS.adoc[FUNCTIONS.adoc] index.\n\n'''\n\n== How To Guide\n\n=== Write new DSL in the _Bashmatic®_ Style\n\nThe following example is the actual code from a soon to be integrated AWS credentials install script. This code below checks that a user has a local `~/.aws/credentials` file needed by the `awscli`, and in the right INI format. If it doesn't find it, it checks for the access key CSV file in the `~/Downloads` folder, and converts that if found. Now, if even that is not found, it prompts the user with instructions on how to generate a new key pair on AWS IAM website, and download it locally, thereby quickly converting and installing it as a proper credentials file. Not bad, for a compact BASH script, right? (of course, you are not seeing all of the involved functions, only the public ones).\n\n[source,bash]\n----\n# define a new function in AWS namespace, related to credentials.\n# name of the function is self-explanatory: it validates credentials\n# and exits if they are invalid.\naws.credentials.validate-or-exit() {\n  aws.credentials.are-valid || {\n    aws.credentials.install-if-missing || bashmatic.exit-or-return 1\n  }\n}\n\naws.credentials.install-if-missing() {\n  aws.credentials.are-present || { # if not present\n    aws.access-key.is-present || aws.access-key.download # attempt to download the key\n    aws.access-key.is-present \u0026\u0026 aws.credentials.check-downloads-folder # attempt to find it in ~/Downloads\n  }\n\n  aws.credentials.are-present || { # final check after all attempts to install credentials\n    error \"Unable to find AWS credentials. Please try again.\" \u0026\u0026 bashmatic.exit-or-return 1\n  }\n\n   bashmatic.exit-or-return 0\n}\n----\n\nNow, *how would you use it in a script?* Let's say you need a script to upload\nsomething to AWS S3. But before you begin, wouldn't it be nice to verify\nthat the credentials exist, and if not – help the user install it? Yes it would.\n\nAnd that is exactly what the code above does, but it looks like a DSL. because\nit _is_ a DSL.\n\nThis script could be your `bin/s3-uploader`\n\n[source, bash]\n----\naws.credentials.validate-or-exit\n# if we are here, that means that AWS credentials have been found.\n# and we can continue with our script.\n----\n\n\n### How can I test if the function was ran as part of a script, or \"sourced-in\"?\n\nSome bash files exists as libraries to be \"sourced in\", and others exist as scripts to be run. But users won't always know what is what, and may try to source in a script that should be run, or vice versa - run a script that should be sourced in.\n\nWhat do you, programmer, do to educate the user about correct usage of your script/library?\n\n_Bashmatic®_ offers a reliable way to test this:\n\n[source,bash]\n----\n#!/usr/bin/env bash\n# load library\nif [[ -f \"${Bashmatic__Init}\" ]]; then source \"${Bashmatic__Init}\"; else source ${BASHMATIC_HOME}/init.sh; fi\nbashmatic.validate-subshell || return 1\n----\n\nIf you'rather require a library to be sourced in, but not run, use the code as follows:\n\n[source,bash]\n----\n#!/usr/bin/env bash\n# load library\nif [[ -f \"${Bashmatic__Init}\" ]]; then source \"${Bashmatic__Init}\"; else source ${BASHMATIC_HOME}/init.sh; fi\nbashmatic.validate-sourced-in || exit 1\n----\n\n=== How can I change the underscan or overscan for an old monitor?\n\nIf you are stuck working on a monitor that does not support switching digit input from TV to PC, NOR does OS-X show the \"underscan\" slider in the Display Preferences, you may be forced to change the underscan manually. The process is a bit tricky, but we have a helpful script to do that:\n\n[source,bash]\n----\n$ source init.sh\n$ change-underscan 5\n----\n\nThis will reduce underscan by 5% compared to the current value. The total value is 10000, and is stored in the file `/var/db/.com.apple.iokit.graphics`. The tricky part is determining which of the display entries map to your problem monitor. This is what the script helps with.\n\nDo not forget to restart after the change.\n\nAcknowledgements: the script is an automation of the method offered on http://ishan.co/external-monitor-underscan[this blog post].\n\n== Contributing\n\nPlease https://github.com/kigster/bashmatic/pulls/new[ submit a pull request] or at least an issue!\n\n=== Running Unit Tests\n\nThe framework comes with a bunch of automated unit tests based on the fantastic framework https://github.com/sstephenson/bats.git[`bats`].\n\nBats is auto-installed by the `bin/specs` script.\n\n==== Run Tests Using the Provided `bin/specs` script\n\nWe use Bats framework for testing, however we provided a convenient wrapper `bin/specs` which installs Bats and its dependencies so that we don't have to worry about installing it manually.\n\nThe script can be run:\n\n1. Without any arguments to run all tests in the `test` folder in parallel by default\n2. You can pass one or more existing test file paths as arguments, eg `bin/specs test/time_test.bats`\n3. Finally, you can pass an abbreviated test file name — eg \"time\" will resolve to `test/time_test.bats`\n\nThe script accepts a bunch of CLI arguments and flags shown below:\n\nimage::doc/img/specs-parallel.png[example,align=center,width=100%]\n\n==== Running Specs Sequentially with `bin/spec -P`\n\nBy the default, `bin/spec` runs tests in parallel, and takes about 20 seconds.\n\nIf you pass the `-P/--no-parallel` flag, it will run sequentially and take about twice as long.\n\nBelow is the screenshot of the tests running in the parallel mode. The script automatically detects that my machine has 16 CPU cores and uses this as a parallization factor.\n\nimage::doc/img/specs.png[example,align=center,width=100%]\n\n==== Run Tests Parallel using the `Makefile`\n\nNote that you can run all tests in parallel using the following make target:\n\n[source,bash]\nmake test\n\nWhile not every single function is tested (far from it), we do try to add tests to the critical ones.\n\nPlease see https://github.com/kigster/bashmatic/blob/main/test/array_test.bats[existing tests] for the examples.\n\n==== Run Tests Sequentially using the `Makefile`\n\nAlternatively, you can run the entire test suite via the Makefile, using one of two targets:\n\n[source,bash]\nmake test-sequential\n\n\n== Copyright \u0026 License\n\nNOTE: © 2016-2022 Konstantin Gredeskoul +\nThis project is distributed under the **MIT License.**\n\n\n\n\n","funding_links":["https://github.com/sponsors/kigster","https://patreon.com/polygroovers","https://liberapay.com/kigster/donate"],"categories":["Shell","bash","Shell Script Development","Libraries"],"sub_categories":["Reusable Things"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkigster%2Fbashmatic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkigster%2Fbashmatic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkigster%2Fbashmatic/lists"}