Squashed 'vendor/git.knownelement.com/ExternalVendorCode/bash3boilerplate/' content from commit 2e878ec
git-subtree-dir: vendor/git.knownelement.com/ExternalVendorCode/bash3boilerplate git-subtree-split: 2e878ec30f0572ad80f34743b6136536cf7c202f
This commit is contained in:
		
							
								
								
									
										7
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
Thanks for contributing to b3bp! As part of your PR, have you:
 | 
			
		||||
 | 
			
		||||
- [ ] Added an item in [CHANGELOG.md](https://github.com/kvz/bash3boilerplate/blob/HEAD/CHANGELOG.md) with attribution?
 | 
			
		||||
- [ ] Added your name to the [README.md](https://github.com/kvz/bash3boilerplate/blob/HEAD/README.md#authors)
 | 
			
		||||
- [ ] Linted your code? (`make test` should do the trick)
 | 
			
		||||
 | 
			
		||||
If so, great! Feel free to replace this message with a description of your work and hit submit!
 | 
			
		||||
							
								
								
									
										5
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
groups:
 | 
			
		||||
  production-dependencies:
 | 
			
		||||
    dependency-type: 'production'
 | 
			
		||||
  development-dependencies:
 | 
			
		||||
    dependency-type: 'development'
 | 
			
		||||
							
								
								
									
										30
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
name: b3bp CI
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - main
 | 
			
		||||
  pull_request:
 | 
			
		||||
    types:
 | 
			
		||||
      - opened
 | 
			
		||||
      - synchronize
 | 
			
		||||
jobs:
 | 
			
		||||
  ci:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          fetch-depth: 1
 | 
			
		||||
      - uses: actions/setup-node@v1
 | 
			
		||||
        with:
 | 
			
		||||
          node-version: 18.x
 | 
			
		||||
      - name: Install
 | 
			
		||||
        run: |
 | 
			
		||||
          corepack yarn
 | 
			
		||||
      - name: Lint
 | 
			
		||||
        env:
 | 
			
		||||
          SHELLCHECK_SEVERITY: warning
 | 
			
		||||
        run: |
 | 
			
		||||
          corepack yarn lint
 | 
			
		||||
      - name: Test
 | 
			
		||||
        run: |
 | 
			
		||||
          corepack yarn test
 | 
			
		||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
.yarn
 | 
			
		||||
assets/build
 | 
			
		||||
env.sh
 | 
			
		||||
node_modules
 | 
			
		||||
npm-debug.log
 | 
			
		||||
							
								
								
									
										3
									
								
								.shellcheckrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.shellcheckrc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
external-sources=true
 | 
			
		||||
shell=bash
 | 
			
		||||
color=always
 | 
			
		||||
							
								
								
									
										8
									
								
								.vscode/bash3boilerplate.code-workspace
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.vscode/bash3boilerplate.code-workspace
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
	"folders": [
 | 
			
		||||
		{
 | 
			
		||||
			"path": ".."
 | 
			
		||||
		}
 | 
			
		||||
	],
 | 
			
		||||
	"settings": {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								.yarnrc.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.yarnrc.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
nodeLinker: node-modules
 | 
			
		||||
							
								
								
									
										175
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
 | 
			
		||||
Here's is a combined todo/done list. You can see what todos are planned for the upcoming release, as well as ideas that may/may not make into a release in `Ideas`.
 | 
			
		||||
 | 
			
		||||
## Ideas
 | 
			
		||||
 | 
			
		||||
Unplanned.
 | 
			
		||||
 | 
			
		||||
- [ ] Better style guide checking (#84)
 | 
			
		||||
 | 
			
		||||
## main
 | 
			
		||||
 | 
			
		||||
Released: TBA.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/2.7.2...main).
 | 
			
		||||
 | 
			
		||||
- [ ]
 | 
			
		||||
 | 
			
		||||
## 2.7.2
 | 
			
		||||
 | 
			
		||||
Released: 2023-08-29
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.4.1...2.7.2).
 | 
			
		||||
 | 
			
		||||
- [x] Upgrade and cleanup node dependencies
 | 
			
		||||
- [x] Remove lanyon-based website in favor of simple redirect to github for bash3boilerplate.sh
 | 
			
		||||
- [x] Make tests pass again
 | 
			
		||||
- [x] Make linting and style checking separate actions
 | 
			
		||||
- [x] Add feature to edit/update comments in ini file (#132, @rfuehrer)
 | 
			
		||||
- [x] Upgrade to `lanyon@0.1.16`
 | 
			
		||||
- [x] Capture correct error_code in err_report (#124, @eval)
 | 
			
		||||
- [x] Enhanced ini file handling: create new file, create new sections, handle default section, read key from given section (@rfuehrer)
 | 
			
		||||
 | 
			
		||||
## v2.4.2
 | 
			
		||||
 | 
			
		||||
Released: 2019-11-07.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.4.1...v2.4.2).
 | 
			
		||||
 | 
			
		||||
- [x] Upgrade to `lanyon@0.1.16`
 | 
			
		||||
- [x] Capture correct error_code in err_report (#124, @eval)
 | 
			
		||||
- [x] Enhanced ini file handling: create new file, create new sections, handle default section, read key from given section (@rfuehrer)
 | 
			
		||||
 | 
			
		||||
## v2.4.1
 | 
			
		||||
 | 
			
		||||
Released: 2019-11-07.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.3.0...v2.4.1).
 | 
			
		||||
 | 
			
		||||
- [x] Upgrade to `lanyon@0.1.7`
 | 
			
		||||
- [x] Allow counting how many times an argument is used (@genesiscloud)
 | 
			
		||||
- [x] Fix typos in megamount (thanks @gsaponaro)
 | 
			
		||||
- [x] Enable color in screen or tmux (#92, @gmasse)
 | 
			
		||||
- [x] Change `egrep` to `grep -E` in test and lib scripts to comply with ShellCheck (#92, @gmasse)
 | 
			
		||||
- [x] Fix typo in FAQ (#92, @gmasse)
 | 
			
		||||
- [x] Fix Travis CI failure on src/templater.sh (@gmasse)
 | 
			
		||||
- [x] Add magic variable which contains full command invocation
 | 
			
		||||
- [x] More contrasted alert and emergency colors (#111 @gmeral)
 | 
			
		||||
- [x] Add support for repeatable arguments (@genesiscloud)
 | 
			
		||||
- [x] Fix remaining warnings with shellcheck v0.7.0 (#107, @genesiscloud)
 | 
			
		||||
 | 
			
		||||
## v2.4.0
 | 
			
		||||
 | 
			
		||||
Released: 2016-12-21.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.3.0...v2.4.0).
 | 
			
		||||
 | 
			
		||||
- [x] Upgrade to `lanyon@0.0.143`
 | 
			
		||||
 | 
			
		||||
## v2.3.0
 | 
			
		||||
 | 
			
		||||
Released: 2016-12-21.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.2.0...v2.3.0).
 | 
			
		||||
 | 
			
		||||
- [x] Add magic variable `__i_am_main_script` to distinguish if b3bp is being sourced or called directly (#45, @zbeekman)
 | 
			
		||||
- [x] Add style checks for tab characters and trailing whitespace (@zbeekman)
 | 
			
		||||
- [x] Add backtracing to help localize errors (#44, @zbeekman)
 | 
			
		||||
- [x] Additional FAQ entries (#47, suggested by @gdevenyi, implemented by @zbeekman)
 | 
			
		||||
- [x] Ensure that shifting over `--` doesn't throw an errexit error (#21, @zbeekman)
 | 
			
		||||
- [x] Add Pull Request template (#83)
 | 
			
		||||
 | 
			
		||||
## v2.2.0
 | 
			
		||||
 | 
			
		||||
Released: 2016-12-21.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.1.0...v2.2.0).
 | 
			
		||||
 | 
			
		||||
- [x] README and FAQ improvements (#66, @mstreuhofer)
 | 
			
		||||
- [x] Add support for sourcing b3bp (#61, @mstreuhofer)
 | 
			
		||||
- [x] Upgrade all Node.js dependencies for development (#78)
 | 
			
		||||
- [x] Switch to http://lanyon.io for static site building, add a new logo
 | 
			
		||||
- [x] Cleanup environment variables (#58, @mstreuhofer)
 | 
			
		||||
- [x] Support multi-line logs (#57, @mstreuhofer)
 | 
			
		||||
- [x] Run shellcheck as part of the acceptance test (#79, @mstreuhofer)
 | 
			
		||||
- [x] Brace all variables, used `[[` instead of `[` (#33, #76, @mstreuhofer)
 | 
			
		||||
- [x] Add automatic usage validation for required args (#22, #65, @mstreuhofer)
 | 
			
		||||
- [x] Remove all usage of eval (@mstreuhofer)
 | 
			
		||||
- [x] Get rid of awk, sed & egrep usage (#71, @mstreuhofer)
 | 
			
		||||
- [x] Fix auto-color-off code (#69, #70, @mstreuhofer)
 | 
			
		||||
- [x] Use shellcheck to find and fix unclean code (#68, #80, @mstreuhofer)
 | 
			
		||||
- [x] Allow for multiline opt description in `__usage` (#7, @mstreuhofer)
 | 
			
		||||
- [x] Allow `__usage` and `__helptext` to be defined before sourcing `main.sh` thus makeing b3bp behave like a library (@mstreuhofer)
 | 
			
		||||
- [x] Add the same License text to each script header (@mstreuhofer)
 | 
			
		||||
 | 
			
		||||
## v2.1.0
 | 
			
		||||
 | 
			
		||||
Released: 2016-11-08.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.0.0...v2.1.0).
 | 
			
		||||
 | 
			
		||||
- [x] Cleanup b3bp variables (adds prefixes across the board) (thanks @mstreuhofer)
 | 
			
		||||
- [x] Add multi-line logging support (thanks @mstreuhofer)
 | 
			
		||||
- [x] Mangle long-option names to allow dashes (thanks @zbeekman)
 | 
			
		||||
- [x] Remove OS detection altogether (#38, thx @zbeekman)
 | 
			
		||||
- [x] Offer the main template for download as http://bash3boilerplate.sh/main.sh
 | 
			
		||||
- [x] Better OS detection (#38, thx @moviuro)
 | 
			
		||||
- [x] Improve README copy (#34, thx galaktos)
 | 
			
		||||
- [x] Fix unquoted variable access within (#34 thx galaktos)
 | 
			
		||||
- [x] For delete-key-friendliness, bundle the commandline definition block along with its parser
 | 
			
		||||
- [x] Less verbose header comments
 | 
			
		||||
- [x] For delete-key-friendliness, don't crash on undeclared help vars
 | 
			
		||||
- [x] Introduce `errtrace`, which is on by default (BREAKING)
 | 
			
		||||
- [x] Add a configurable `helptext` that is left alone by the parses and allows you to have a richer help
 | 
			
		||||
- [x] Add a simple documentation website
 | 
			
		||||
- [x] Add best practice of using `__double_underscore_prefixed_vars` to indicate global variables that are solely controlled inside your script
 | 
			
		||||
- [x] Make license more permissive by not requiring distribution of the LICENSE file if the copyright & attribution comments are left intact
 | 
			
		||||
- [x] Respect `--no-color` by setting the `NO_COLOR` flag in `main.sh` (#25, thx @gdevenyi)
 | 
			
		||||
- [x] Split out changelog into separate file
 | 
			
		||||
- [x] Added a [FAQ](./FAQ.md) (#15, #14, thanks @rouson)
 | 
			
		||||
- [x] Fix Travis OSX testing (before, it would silently pass failures) (#10)
 | 
			
		||||
- [x] Enable dashes in long, GNU style options, as well as numbers (thanks @zbeekman)
 | 
			
		||||
 | 
			
		||||
## v2.0.0
 | 
			
		||||
 | 
			
		||||
Released: 2016-02-17.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.2.1...v2.0.0).
 | 
			
		||||
 | 
			
		||||
- [x] Add tests for `templater` and follow Library export best practices
 | 
			
		||||
- [x] Add tests for `ini_val` and follow Library export best practices
 | 
			
		||||
- [x] Add tests for `parse_url` and follow Library export best practices
 | 
			
		||||
- [x] Add tests for `megamount` and follow Library export best practices
 | 
			
		||||
- [x] Remove `bump` from `src` (BREAKING)
 | 
			
		||||
- [x] Remove `semver` from `src` (BREAKING)
 | 
			
		||||
 | 
			
		||||
## v1.2.1
 | 
			
		||||
 | 
			
		||||
Released: 2016-02-17.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.2.0...v1.2.1).
 | 
			
		||||
 | 
			
		||||
- [x] Add Travis CI automated testing for OSX (thanks @zbeekman)
 | 
			
		||||
 | 
			
		||||
## v1.2.0
 | 
			
		||||
 | 
			
		||||
Released: 2016-02-16.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.1.0...v1.2.0).
 | 
			
		||||
 | 
			
		||||
- [x] Allow disabling colors via `NO_COLOR` environment variable
 | 
			
		||||
- [x] Enable `errexit`, `nounset` and `pipefail` options at the top of the script already
 | 
			
		||||
- [x] More refined colors (thanks @arathai)
 | 
			
		||||
- [x] Add a changelog to the README
 | 
			
		||||
- [x] Add `__os` magic var (limited to discovering OSX and defaulting to Linux for now)
 | 
			
		||||
- [x] Add `__base` magic var (`main`, if the source script is `main.sh`)
 | 
			
		||||
- [x] Enable long, GNU style options (thanks @zbeekman)
 | 
			
		||||
- [x] Add Travis CI automated testing for Linux
 | 
			
		||||
 | 
			
		||||
## v1.1.0
 | 
			
		||||
 | 
			
		||||
Released: 2015-06-29.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.0.3...v1.1.0).
 | 
			
		||||
 | 
			
		||||
- [x] Add `ALLOW_REMAINDERS` configuration to templater
 | 
			
		||||
- [x] Fix typo: 'debugmdoe' to 'debugmode' (thanks @jokajak)
 | 
			
		||||
- [x] Use `${BASH_SOURCE[0]}` for `__file` instead of `${0}`
 | 
			
		||||
 | 
			
		||||
## v1.0.3
 | 
			
		||||
 | 
			
		||||
Released: 2014-11-02.
 | 
			
		||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/5db569125319a89b9561b434db84e4d91faefb63...v1.0.3).
 | 
			
		||||
 | 
			
		||||
- [x] Add `ini_val`, `megamount`, `parse_url`
 | 
			
		||||
- [x] Add re-usable libraries in `./src`
 | 
			
		||||
- [x] Use npm as an additional distribution channel
 | 
			
		||||
							
								
								
									
										171
									
								
								FAQ.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								FAQ.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,171 @@
 | 
			
		||||
[This document is formatted with GitHub-Flavored Markdown. ]: #
 | 
			
		||||
[For better viewing, including hyperlinks, read it online at ]: #
 | 
			
		||||
[https://github.com/kvz/bash3boilerplate/blob/HEAD/FAQ.md ]: #
 | 
			
		||||
 | 
			
		||||
## Contents
 | 
			
		||||
 | 
			
		||||
- [What is a CLI](#what-is-a-cli)?
 | 
			
		||||
- [How do I incorporate BASH3 Boilerplate into my own project](#how-do-i-incorporate-bash3-boilerplate-into-my-own-project)?
 | 
			
		||||
- [How do I add a command-line flag](#how-do-i-add-a-command-line-flag)?
 | 
			
		||||
- [How do I access the value of a command-line argument](#how-do-i-access-the-value-of-a-command-line-argument)?
 | 
			
		||||
- [What is a magic variable](#what-is-a-magic-variable)?
 | 
			
		||||
- [How do I submit an issue report](#how-do-i-submit-an-issue-report)?
 | 
			
		||||
- [How can I contribute to this project](#how-can-i-contribute-to-this-project)?
 | 
			
		||||
- [Why are you typing BASH in all caps](#why-are-you-typing-bash-in-all-caps)?
 | 
			
		||||
- [You are saying you are portable, but why won't b3bp code run in dash / busybox / posh / ksh / mksh / zsh](#you-are-saying-you-are-portable-but-why-wont-b3bp-code-run-in-dash--busybox--posh--ksh--mksh--zsh)?
 | 
			
		||||
- [How do I do Operating System detection](#how-do-i-do-operating-system-detection)?
 | 
			
		||||
- [How do I access a potentially unset (environment) variable](#how-do-i-access-a-potentially-unset-environment-variable)?
 | 
			
		||||
- [How can I detect or trap CTRL-C and other signals](#how-can-i-detect-or-trap-ctrl-c-and-other-signals)?
 | 
			
		||||
- [How can I get the PID of my running script](how-can-i-get-the-pid-of-my-running-script)?
 | 
			
		||||
 | 
			
		||||
<!--more-->
 | 
			
		||||
 | 
			
		||||
# Frequently Asked Questions
 | 
			
		||||
 | 
			
		||||
## What is a CLI?
 | 
			
		||||
 | 
			
		||||
A "CLI" is a [command-line interface](https://en.wikipedia.org/wiki/Command-line_interface).
 | 
			
		||||
 | 
			
		||||
## How do I incorporate BASH3 Boilerplate into my own project?
 | 
			
		||||
 | 
			
		||||
You can incorporate BASH3 Boilerplate into your project in one of two ways:
 | 
			
		||||
 | 
			
		||||
1. Copy the desired portions of [`main.sh`](http://bash3boilerplate.sh/main.sh) into your own script.
 | 
			
		||||
1. Download [`main.sh`](http://bash3boilerplate.sh/main.sh) and start pressing the delete-key to remove unwanted things
 | 
			
		||||
 | 
			
		||||
Once the `main.sh` has been tailor-made for your project, you can either append your own script in the same file, or source it in the following ways:
 | 
			
		||||
 | 
			
		||||
1. Copy [`main.sh`](http://bash3boilerplate.sh/main.sh) into the same directory as your script and then edit and embed it into your script using Bash's `source` include feature, e.g.:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
source main.sh
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
1. Source [`main.sh`](http://bash3boilerplate.sh/main.sh) in your script or at the command line:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
source main.sh
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## How do I add a command-line flag?
 | 
			
		||||
 | 
			
		||||
1. Copy the line from the `main.sh` [read block](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L109-L115) that most resembles the desired behavior and paste the line into the same block.
 | 
			
		||||
1. Edit the single-character (e.g., `-d`) and, if present, the multi-character (e.g., `--debug`) versions of the flag in the copied line.
 | 
			
		||||
1. Omit the `[arg]` text in the copied line, if the desired flag takes no arguments.
 | 
			
		||||
1. Omit or edit the text after `Default=` to set or not set default values, respectively.
 | 
			
		||||
1. Omit the `Required.` text, if the flag is optional.
 | 
			
		||||
 | 
			
		||||
## How do I access the value of a command-line argument?
 | 
			
		||||
 | 
			
		||||
To find out the value of an argument, append the corresponding single-character flag to the text `$arg_`. For example, if the [read block]
 | 
			
		||||
contains the line
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
   -t --temp  [arg] Location of tempfile. Default="/tmp/bar"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
then you can evaluate the corresponding argument and assign it to a variable as follows:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
__temp_file_name="${arg_t}"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## What is a magic variable?
 | 
			
		||||
 | 
			
		||||
The [magic variables](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L26-L28) in `main.sh` are special in that they have a different value, depending on your environment. You can use `${__file}` to get a reference to your current script, and `${__dir}` to get a reference to the directory it lives in. This is not to be confused with the location of the calling script that might be sourcing the `${__file}`, which is accessible via `${0}`, or the current directory of the administrator running the script, accessible via `$(pwd)`.
 | 
			
		||||
 | 
			
		||||
## How do I submit an issue report?
 | 
			
		||||
 | 
			
		||||
Please visit our [Issues](https://github.com/kvz/bash3boilerplate/issues) page.
 | 
			
		||||
 | 
			
		||||
## How can I contribute to this project?
 | 
			
		||||
 | 
			
		||||
Please fork this repository. After that, create a branch containing your suggested changes and submit a pull request based on the main branch
 | 
			
		||||
of <https://github.com/kvz/bash3boilerplate/>. We are always more than happy to accept your contributions!
 | 
			
		||||
 | 
			
		||||
## Why are you typing BASH in all caps?
 | 
			
		||||
 | 
			
		||||
As an acronym, Bash stands for Bourne-again shell, and is usually written with one uppercase.
 | 
			
		||||
This project's name, however, is "BASH3 Boilerplate". It is a reference to
 | 
			
		||||
"[HTML5 Boilerplate](https://html5boilerplate.com/)", which was founded to serve a similar purpose,
 | 
			
		||||
only for crafting webpages.
 | 
			
		||||
Somewhat inconsistent – but true to Unix ancestry – the abbreviation for our project is "b3bp".
 | 
			
		||||
 | 
			
		||||
## You are saying you are portable, but why won't b3bp code run in dash / busybox / posh / ksh / mksh / zsh?
 | 
			
		||||
 | 
			
		||||
When we say _portable_, we mean across Bash versions. Bash is widespread and most systems
 | 
			
		||||
offer at least version 3 of it. Make sure you have that available and b3bp will work for you.
 | 
			
		||||
 | 
			
		||||
We run automated tests to make sure that it will. Here is some proof for the following platforms:
 | 
			
		||||
 | 
			
		||||
- [Linux](https://travis-ci.org/kvz/bash3boilerplate/jobs/109804166#L91-L94) `GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)`
 | 
			
		||||
- [OSX](https://travis-ci.org/kvz/bash3boilerplate/jobs/109804167#L2453-L2455) `GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)`
 | 
			
		||||
 | 
			
		||||
This portability, however, does not mean that we try to be compatible with
 | 
			
		||||
KornShell, Zsh, posh, yash, dash, or other shells. We allow syntax that would explode if
 | 
			
		||||
you pasted it in anything but Bash 3 and up.
 | 
			
		||||
 | 
			
		||||
## How do I do Operating System detection?
 | 
			
		||||
 | 
			
		||||
We used to offer a magic `__os` variable, but we quickly [discovered](https://github.com/kvz/bash3boilerplate/issues/38) that it would be hard
 | 
			
		||||
to create a satisfactory abstraction that is not only correct, but also covers enough use-cases,
 | 
			
		||||
while still having a relatively small footprint in `main.sh`.
 | 
			
		||||
 | 
			
		||||
For simple OS detection, we recommend using the `${OSTYPE}` variable available in Bash as
 | 
			
		||||
is demoed in [this stackoverflow post](http://stackoverflow.com/a/8597411/151666):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
if [[ "${OSTYPE}" = "linux-gnu" ]]; then
 | 
			
		||||
  echo "GNU Linux"
 | 
			
		||||
elif [[ "${OSTYPE}" = "darwin"* ]]; then
 | 
			
		||||
  echo "Mac OSX"
 | 
			
		||||
elif [[ "${OSTYPE}" = "cygwin" ]]; then
 | 
			
		||||
  echo "POSIX compatibility layer and Linux environment emulation for Windows"
 | 
			
		||||
elif [[ "${OSTYPE}" = "msys" ]]; then
 | 
			
		||||
  echo "Lightweight shell and GNU utilities compiled for Windows (part of MinGW)"
 | 
			
		||||
elif [[ "${OSTYPE}" = "win32" ]]; then
 | 
			
		||||
  echo "I'm not sure this can happen."
 | 
			
		||||
elif [[ "${OSTYPE}" = "freebsd"* ]]; then
 | 
			
		||||
  echo "..."
 | 
			
		||||
else
 | 
			
		||||
  echo "Unknown."
 | 
			
		||||
fi
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## How do I access a potentially unset (environment) variable?
 | 
			
		||||
 | 
			
		||||
The set -o nounset line in `main.sh` causes error termination when an unset environment variables is detected as unbound. There are multiple ways to avoid this.
 | 
			
		||||
 | 
			
		||||
Some code to illustrate:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# method 1
 | 
			
		||||
echo ${NAME1:-Damian} # echos Damian, $NAME1 is still unset
 | 
			
		||||
# method 2
 | 
			
		||||
echo ${NAME2:=Damian} # echos Damian, $NAME2 is set to Damian
 | 
			
		||||
# method 3
 | 
			
		||||
NAME3=${NAME3:-Damian}; echo ${NAME3} # echos Damian, $NAME3 is set to Damian
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This subject is briefly touched on as well in the [Safety and Portability section under point 5](README.md#safety-and-portability). b3bp currently uses [method 1](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L252) when we want to access a variable that could be undeclared, and [method 3](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L31) when we also want to set a default to an undeclared variable, because we feel it is more readable than method 2. We feel `:=` is easily overlooked, and not very beginner friendly. Method 3 seems more explicit in that regard in our humble opinion.
 | 
			
		||||
 | 
			
		||||
## How can I detect or trap Ctrl-C and other signals?
 | 
			
		||||
 | 
			
		||||
You can trap [Unix signals](https://en.wikipedia.org/wiki/Unix_signal) like [Ctrl-C](https://en.wikipedia.org/wiki/Control-C) with code similar to:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# trap ctrl-c and call ctrl_c()
 | 
			
		||||
trap ctrl_c INT
 | 
			
		||||
 | 
			
		||||
function ctrl_c() {
 | 
			
		||||
        echo "** Trapped CTRL-C"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
See http://mywiki.wooledge.org/SignalTrap for a list of signals, examples, and an in depth discussion.
 | 
			
		||||
 | 
			
		||||
## How can I get the PID of my running script?
 | 
			
		||||
 | 
			
		||||
The PID of a running script is contained in the `${$}` variable. This is _not_ the pid of any subshells. With Bash 4 you can get the PID of your subshell with `${BASHPID}`. For a comprehensive list of Bash built in variables see, e.g., http://www.tldp.org/LDP/abs/html/internalvariables.html
 | 
			
		||||
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
							
								
								
									
										59
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
# Licensed under MIT.
 | 
			
		||||
# Copyright (2016) by Kevin van Zonneveld https://twitter.com/kvz
 | 
			
		||||
#
 | 
			
		||||
# https://www.npmjs.com/package/fakefile
 | 
			
		||||
#
 | 
			
		||||
# Please do not edit this file directly, but propose changed upstream instead:
 | 
			
		||||
# https://github.com/kvz/fakefile/blob/main/Makefile
 | 
			
		||||
#
 | 
			
		||||
# This Makefile offers convience shortcuts into any Node.js project that utilizes npm scripts.
 | 
			
		||||
# It functions as a wrapper around the actual listed in `package.json`
 | 
			
		||||
# So instead of typing:
 | 
			
		||||
#
 | 
			
		||||
#  $ npm script build:assets
 | 
			
		||||
#
 | 
			
		||||
# you could also type:
 | 
			
		||||
#
 | 
			
		||||
#  $ make build-assets
 | 
			
		||||
#
 | 
			
		||||
# Notice that colons (:) are replaced by dashes for Makefile compatibility.
 | 
			
		||||
#
 | 
			
		||||
# The benefits of this wrapper are:
 | 
			
		||||
#
 | 
			
		||||
# - You get to keep the the scripts package.json, which is more portable
 | 
			
		||||
#   (Makefiles & Windows are harder to mix)
 | 
			
		||||
# - Offer a polite way into the project for developers coming from different
 | 
			
		||||
#   languages (npm scripts is obviously very Node centric)
 | 
			
		||||
# - Profit from better autocomplete (make <TAB><TAB>) than npm currently offers.
 | 
			
		||||
#   OSX users will have to install bash-completion
 | 
			
		||||
#   (http://davidalger.com/development/bash-completion-on-os-x-with-brew/)
 | 
			
		||||
 | 
			
		||||
ifeq ($(shell test -e ./yarn.lock && echo -n yes),yes)
 | 
			
		||||
	RUNNER=yarn
 | 
			
		||||
	INSTALLER=yarn install
 | 
			
		||||
else
 | 
			
		||||
	RUNNER=npm run
 | 
			
		||||
	INSTALLER=npm install
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
define npm_script_targets
 | 
			
		||||
TARGETS := $(shell \
 | 
			
		||||
	node -e 'for (var k in require("./package.json").scripts) {console.log(k.replace(/:/g, "-"));}'
 | 
			
		||||
		| grep -v -E "^install$$"
 | 
			
		||||
)
 | 
			
		||||
$$(TARGETS):
 | 
			
		||||
	$(RUNNER) $(shell \
 | 
			
		||||
							node -e 'for (var k in require("./package.json").scripts) {console.log(k.replace(/:/g, "-"), k);}'
 | 
			
		||||
								| grep -E "^$(MAKECMDGOALS)\s"
 | 
			
		||||
								| head -n1
 | 
			
		||||
								| awk '{print $$2}'
 | 
			
		||||
							)
 | 
			
		||||
 | 
			
		||||
.PHONY: $$(TARGETS)
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
$(eval $(call npm_script_targets))
 | 
			
		||||
 | 
			
		||||
# These npm run scripts are available, without needing to be mentioned in `package.json`
 | 
			
		||||
install:
 | 
			
		||||
	$(INSTALLER)
 | 
			
		||||
							
								
								
									
										175
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
[This document is formatted with GitHub-Flavored Markdown. ]: #
 | 
			
		||||
[For better viewing, including hyperlinks, read it online at ]: #
 | 
			
		||||
[https://github.com/kvz/bash3boilerplate/blob/HEAD/README.md]: #
 | 
			
		||||
 | 
			
		||||
- [Overview](#overview)
 | 
			
		||||
- [Goals](#goals)
 | 
			
		||||
- [Features](#features)
 | 
			
		||||
- [Installation](#installation)
 | 
			
		||||
- [Changelog](#changelog)
 | 
			
		||||
- [Frequently Asked Questions](#frequently-asked-questions)
 | 
			
		||||
- [Best Practices](#best-practices)
 | 
			
		||||
- [Who uses b3bp](#who-uses-b3bp)
 | 
			
		||||
- [Authors](#authors)
 | 
			
		||||
- [License](#license)
 | 
			
		||||
 | 
			
		||||
## Overview
 | 
			
		||||
 | 
			
		||||
<!--more-->
 | 
			
		||||
 | 
			
		||||
When hacking up Bash scripts, there are often things such as logging or command-line argument parsing that:
 | 
			
		||||
 | 
			
		||||
- You need every time
 | 
			
		||||
- Come with a number of pitfalls you want to avoid
 | 
			
		||||
- Keep you from your actual work
 | 
			
		||||
 | 
			
		||||
Here's an attempt to bundle those things in a generalized way so that
 | 
			
		||||
they are reusable as-is in most scripts.
 | 
			
		||||
 | 
			
		||||
We call it "BASH3 Boilerplate" or b3bp for short.
 | 
			
		||||
 | 
			
		||||
## Goals
 | 
			
		||||
 | 
			
		||||
Delete-Key-**Friendly**. Instead of introducing packages, includes, compilers, etc., we propose using [`main.sh`](https://bash3boilerplate.sh/main.sh) as a base and removing the parts you don't need.
 | 
			
		||||
While this may feel a bit archaic at first, it is exactly the strength of Bash scripts that we should want to embrace.
 | 
			
		||||
 | 
			
		||||
**Portable**. We are targeting Bash 3 (OSX still ships
 | 
			
		||||
with 3, for instance). If you are going to ask people to install
 | 
			
		||||
Bash 4 first, you might as well pick a more advanced language as a
 | 
			
		||||
dependency.
 | 
			
		||||
 | 
			
		||||
## Features
 | 
			
		||||
 | 
			
		||||
- Conventions that will make sure that all your scripts follow the same, battle-tested structure
 | 
			
		||||
- Safe by default (break on error, pipefail, etc.)
 | 
			
		||||
- Configuration by environment variables
 | 
			
		||||
- Simple command-line argument parsing that requires no external dependencies. Definitions are parsed from help info, ensuring there will be no duplication
 | 
			
		||||
- Helpful magic variables like `__file` and `__dir`
 | 
			
		||||
- Logging that supports colors and is compatible with [Syslog Severity levels](https://en.wikipedia.org/wiki/Syslog#Severity_levels), as well as the [twelve-factor](https://12factor.net/) guidelines
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
There are three different ways to install b3bp:
 | 
			
		||||
 | 
			
		||||
### Option 1: Download the main template
 | 
			
		||||
 | 
			
		||||
Use curl or wget to download the source and save it as your script. Then you can start deleting the unwanted bits, and adding your own logic.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
wget https://bash3boilerplate.sh/main.sh
 | 
			
		||||
vim main.sh
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Option 2: Clone the entire project
 | 
			
		||||
 | 
			
		||||
Besides `main.sh`, this will also get you the entire b3bp repository. This includes a few extra functions that we keep in the `./src` directory.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
git clone git@github.com:kvz/bash3boilerplate.git
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Option 3: Require via npm
 | 
			
		||||
 | 
			
		||||
As of `v1.0.3`, b3bp can also be installed as a Node module, meaning you can define it as a dependency in `package.json` via:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm init
 | 
			
		||||
npm install --save --save-exact bash3boilerplate
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Even though this option introduces a Node.js dependency, it does allow for easy version pinning and distribution in environments that already have this prerequisite. This is, however, entirely optional and nothing prevents you from ignoring this possibility.
 | 
			
		||||
 | 
			
		||||
## Changelog
 | 
			
		||||
 | 
			
		||||
Please see the [CHANGELOG.md](./CHANGELOG.md) file.
 | 
			
		||||
 | 
			
		||||
## Frequently Asked Questions
 | 
			
		||||
 | 
			
		||||
Please see the [FAQ.md](./FAQ.md) file.
 | 
			
		||||
 | 
			
		||||
## Best practices
 | 
			
		||||
 | 
			
		||||
As of `v1.0.3`, b3bp offers some nice re-usable libraries in `./src`. In order to make the snippets in `./src` more useful, we recommend the following guidelines.
 | 
			
		||||
 | 
			
		||||
### Function packaging
 | 
			
		||||
 | 
			
		||||
It is nice to have a Bash package that can not only be used in the terminal, but also invoked as a command line function. In order to achieve this, the exporting of your functionality _should_ follow this pattern:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
if [[ "${BASH_SOURCE[0]}" = "${0}" ]]; then
 | 
			
		||||
  my_script "${@}"
 | 
			
		||||
  exit $?
 | 
			
		||||
fi
 | 
			
		||||
export -f my_script
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This allows a user to `source` your script or invoke it as a script.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# Running as a script
 | 
			
		||||
$ ./my_script.sh some args --blah
 | 
			
		||||
# Sourcing the script
 | 
			
		||||
$ source my_script.sh
 | 
			
		||||
$ my_script some more args --blah
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
(taken from the [bpkg](https://raw.githubusercontent.com/bpkg/bpkg/HEAD/README.md) project)
 | 
			
		||||
 | 
			
		||||
### Scoping
 | 
			
		||||
 | 
			
		||||
1. In functions, use `local` before every variable declaration.
 | 
			
		||||
1. Use `UPPERCASE_VARS` to indicate environment variables that can be controlled outside your script.
 | 
			
		||||
1. Use `__double_underscore_prefixed_vars` to indicate global variables that are solely controlled inside your script, with the exception of arguments that are already prefixed with `arg_`, as well as functions, over which b3bp poses no restrictions.
 | 
			
		||||
 | 
			
		||||
### Coding style
 | 
			
		||||
 | 
			
		||||
1. Use two spaces for tabs, do not use tab characters.
 | 
			
		||||
1. Do not introduce whitespace at the end of lines or on blank lines as they obfuscate version control diffs.
 | 
			
		||||
1. Use long options (`logger --priority` vs `logger -p`). If you are on the CLI, abbreviations make sense for efficiency. Nevertheless, when you are writing reusable scripts, a few extra keystrokes will pay off in readability and avoid ventures into man pages in the future, either by you or your collaborators. Similarly, we prefer `set -o nounset` over `set -u`.
 | 
			
		||||
1. Use a single equal sign when checking `if [[ "${NAME}" = "Kevin" ]]`; double or triple signs are not needed.
 | 
			
		||||
1. Use the new bash builtin test operator (`[[ ... ]]`) rather than the old single square bracket test operator or explicit call to `test`.
 | 
			
		||||
 | 
			
		||||
### Safety and Portability
 | 
			
		||||
 | 
			
		||||
1. Use `{}` to enclose your variables. Otherwise, Bash will try to access the `$ENVIRONMENT_app` variable in `/srv/$ENVIRONMENT_app`, whereas you probably intended `/srv/${ENVIRONMENT}_app`. Since it is easy to miss cases like this, we recommend that you make enclosing a habit.
 | 
			
		||||
1. Use `set`, rather than relying on a shebang like `#!/usr/bin/env bash -e`, since that is neutralized when someone runs your script as `bash yourscript.sh`.
 | 
			
		||||
1. Use `#!/usr/bin/env bash`, as it is more portable than `#!/bin/bash`.
 | 
			
		||||
1. Use `${BASH_SOURCE[0]}` if you refer to current file, even if it is sourced by a parent script. In other cases, use `${0}`.
 | 
			
		||||
1. Use `:-` if you want to test variables that could be undeclared. For instance, with `if [[ "${NAME:-}" = "Kevin" ]]`, `$NAME` will evaluate to `Kevin` if the variable is empty. The variable itself will remain unchanged. The syntax to assign a default value is `${NAME:=Kevin}`.
 | 
			
		||||
 | 
			
		||||
## Who uses b3bp?
 | 
			
		||||
 | 
			
		||||
- [Transloadit](https://transloadit.com)
 | 
			
		||||
- [OpenCoarrays](https://www.opencoarrays.org)
 | 
			
		||||
- [Sourcery Institute](https://www.sourceryinstitute.org)
 | 
			
		||||
- [Computational Brain Anatomy Laboratory](https://cobralab.ca/)
 | 
			
		||||
- [Genesis Cloud](https://genesiscloud.com/)
 | 
			
		||||
 | 
			
		||||
We are looking for endorsements! Are you also using b3bp? [Let us know](https://github.com/kvz/bash3boilerplate/issues/new?title=I%20use%20b3bp) and get listed.
 | 
			
		||||
 | 
			
		||||
## Authors
 | 
			
		||||
 | 
			
		||||
- [Kevin van Zonneveld](https://kvz.io)
 | 
			
		||||
- [Izaak Beekman](https://izaakbeekman.com/)
 | 
			
		||||
- [Manuel Streuhofer](https://github.com/mstreuhofer)
 | 
			
		||||
- [Alexander Rathai](mailto:Alexander.Rathai@gmail.com)
 | 
			
		||||
- [Dr. Damian Rouson](https://www.sourceryinstitute.org/) (documentation, feedback)
 | 
			
		||||
- [@jokajak](https://github.com/jokajak) (documentation)
 | 
			
		||||
- [Gabriel A. Devenyi](https://staticwave.ca/) (feedback)
 | 
			
		||||
- [@bravo-kernel](https://github.com/bravo-kernel) (feedback)
 | 
			
		||||
- [@skanga](https://github.com/skanga) (feedback)
 | 
			
		||||
- [galaktos](https://www.reddit.com/user/galaktos) (feedback)
 | 
			
		||||
- [@moviuro](https://github.com/moviuro) (feedback)
 | 
			
		||||
- [Giovanni Saponaro](https://github.com/gsaponaro) (feedback)
 | 
			
		||||
- [Germain Masse](https://github.com/gmasse)
 | 
			
		||||
- [A. G. Madi](https://github.com/warpengineer)
 | 
			
		||||
- [Lukas Stockner](mailto:oss@genesiscloud.com)
 | 
			
		||||
- [Gert Goet](https://github.com/eval)
 | 
			
		||||
- [@rfuehrer](https://github.com/rfuehrer)
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2013 Kevin van Zonneveld and [contributors](https://github.com/kvz/bash3boilerplate#authors).
 | 
			
		||||
Licensed under [MIT](https://raw.githubusercontent.com/kvz/bash3boilerplate/HEAD/LICENSE).
 | 
			
		||||
You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
as you leave these references intact in the header comments of your source files.
 | 
			
		||||
							
								
								
									
										1
									
								
								docs/CNAME
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docs/CNAME
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
bash3boilerplate.sh
 | 
			
		||||
							
								
								
									
										15
									
								
								docs/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								docs/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <meta
 | 
			
		||||
      http-equiv="refresh"
 | 
			
		||||
      content="0;url=https://github.com/kvz/bash3boilerplate"
 | 
			
		||||
    />
 | 
			
		||||
    <title>Redirecting...</title>
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    If you are not redirected,
 | 
			
		||||
    <a href="https://github.com/kvz/bash3boilerplate">click here</a>.
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										147
									
								
								example.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										147
									
								
								example.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# This file:
 | 
			
		||||
#
 | 
			
		||||
#  - Demos BASH3 Boilerplate (change this for your script)
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
#
 | 
			
		||||
#  LOG_LEVEL=7 ./example.sh -f /tmp/x -d (change this for your script)
 | 
			
		||||
#
 | 
			
		||||
# Based on a template by BASH3 Boilerplate v2.3.0
 | 
			
		||||
# http://bash3boilerplate.sh/#authors
 | 
			
		||||
#
 | 
			
		||||
# The MIT License (MIT)
 | 
			
		||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
# as you leave these references intact in the header comments of your source files.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### BASH3 Boilerplate (b3bp) Header
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# Commandline options. This defines the usage page, and is used to parse cli
 | 
			
		||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
 | 
			
		||||
# - A short option must be preset for every long option; but every short option
 | 
			
		||||
#   need not have a long option
 | 
			
		||||
# - `--` is respected as the separator between options and arguments
 | 
			
		||||
# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
 | 
			
		||||
#   you can use bash variables to work around this (so use ${HOME} instead)
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
 | 
			
		||||
  -f --file  [arg] Filename to process. Required.
 | 
			
		||||
  -t --temp  [arg] Location of tempfile. Default="/tmp/bar"
 | 
			
		||||
  -v               Enable verbose mode, print script as it is executed
 | 
			
		||||
  -d --debug       Enables debug mode
 | 
			
		||||
  -h --help        This page
 | 
			
		||||
  -n --no-color    Disable color output
 | 
			
		||||
  -1 --one         Do just one thing
 | 
			
		||||
  -i --input [arg] File to process. Can be repeated.
 | 
			
		||||
  -x               Specify a flag. Can be repeated.
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
# shellcheck source=main.sh
 | 
			
		||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/main.sh"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Signal trapping and backtracing
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
function __b3bp_cleanup_before_exit () {
 | 
			
		||||
  info "Cleaning up. Done"
 | 
			
		||||
}
 | 
			
		||||
trap __b3bp_cleanup_before_exit EXIT
 | 
			
		||||
 | 
			
		||||
# requires `set -o errtrace`
 | 
			
		||||
__b3bp_err_report() {
 | 
			
		||||
    local error_code=${?}
 | 
			
		||||
    # shellcheck disable=SC2154
 | 
			
		||||
    error "Error in ${__file} in function ${1} on line ${2}"
 | 
			
		||||
    exit ${error_code}
 | 
			
		||||
}
 | 
			
		||||
# Uncomment the following line for always providing an error backtrace
 | 
			
		||||
# trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# debug mode
 | 
			
		||||
if [[ "${arg_d:?}" = "1" ]]; then
 | 
			
		||||
  set -o xtrace
 | 
			
		||||
  PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
 | 
			
		||||
  LOG_LEVEL="7"
 | 
			
		||||
  # Enable error backtracing
 | 
			
		||||
  trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# verbose mode
 | 
			
		||||
if [[ "${arg_v:?}" = "1" ]]; then
 | 
			
		||||
  set -o verbose
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# no color mode
 | 
			
		||||
if [[ "${arg_n:?}" = "1" ]]; then
 | 
			
		||||
  NO_COLOR="true"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# help mode
 | 
			
		||||
if [[ "${arg_h:?}" = "1" ]]; then
 | 
			
		||||
  # Help exists with code 1
 | 
			
		||||
  help "Help using ${0}"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Validation. Error out if the things required for your script are not present
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
[[ "${arg_f:-}" ]]     || help      "Setting a filename with -f or --file is required"
 | 
			
		||||
[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Runtime
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2154
 | 
			
		||||
info "__i_am_main_script: ${__i_am_main_script}"
 | 
			
		||||
# shellcheck disable=SC2154
 | 
			
		||||
info "__file: ${__file}"
 | 
			
		||||
# shellcheck disable=SC2154
 | 
			
		||||
info "__dir: ${__dir}"
 | 
			
		||||
# shellcheck disable=SC2154
 | 
			
		||||
info "__base: ${__base}"
 | 
			
		||||
info "OSTYPE: ${OSTYPE}"
 | 
			
		||||
 | 
			
		||||
info "arg_f: ${arg_f}"
 | 
			
		||||
info "arg_d: ${arg_d}"
 | 
			
		||||
info "arg_v: ${arg_v}"
 | 
			
		||||
info "arg_h: ${arg_h}"
 | 
			
		||||
if [[ -n "${arg_i:-}" ]]; then
 | 
			
		||||
  info "arg_i: ${#arg_i[@]}"
 | 
			
		||||
  for input_file in "${arg_i[@]}"; do
 | 
			
		||||
    info " - ${input_file}"
 | 
			
		||||
  done
 | 
			
		||||
else
 | 
			
		||||
  info "arg_i: 0"
 | 
			
		||||
fi
 | 
			
		||||
# shellcheck disable=SC2015
 | 
			
		||||
[[ -n "${arg_x:-}" ]] && info "arg_x: ${#arg_x[@]}" || info "arg_x: 0"
 | 
			
		||||
 | 
			
		||||
info "$(echo -e "multiple lines example - line #1\\nmultiple lines example - line #2\\nimagine logging the output of 'ls -al /path/'")"
 | 
			
		||||
 | 
			
		||||
# All of these go to STDERR, so you can use STDOUT for piping machine readable information to other software
 | 
			
		||||
debug "Info useful to developers for debugging the application, not useful during operations."
 | 
			
		||||
info "Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required."
 | 
			
		||||
notice "Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required."
 | 
			
		||||
warning "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time."
 | 
			
		||||
error "Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time."
 | 
			
		||||
critical "Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection."
 | 
			
		||||
alert "Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection."
 | 
			
		||||
emergency "A \"panic\" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call."
 | 
			
		||||
							
								
								
									
										453
									
								
								main.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										453
									
								
								main.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,453 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# This file:
 | 
			
		||||
#
 | 
			
		||||
#  - Demos BASH3 Boilerplate (change this for your script)
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
#
 | 
			
		||||
#  LOG_LEVEL=7 ./main.sh -f /tmp/x -d (change this for your script)
 | 
			
		||||
#
 | 
			
		||||
# Based on a template by BASH3 Boilerplate vv2.7.2
 | 
			
		||||
# http://bash3boilerplate.sh/#authors
 | 
			
		||||
#
 | 
			
		||||
# The MIT License (MIT)
 | 
			
		||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
# as you leave these references intact in the header comments of your source files.
 | 
			
		||||
 | 
			
		||||
# Exit on error. Append "|| true" if you expect an error.
 | 
			
		||||
set -o errexit
 | 
			
		||||
# Exit on error inside any functions or subshells.
 | 
			
		||||
set -o errtrace
 | 
			
		||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
 | 
			
		||||
set -o nounset
 | 
			
		||||
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
 | 
			
		||||
set -o pipefail
 | 
			
		||||
# Turn on traces, useful while debugging but commented out by default
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
 | 
			
		||||
  __i_am_main_script="0" # false
 | 
			
		||||
 | 
			
		||||
  if [[ "${__usage+x}" ]]; then
 | 
			
		||||
    if [[ "${BASH_SOURCE[1]}" = "${0}" ]]; then
 | 
			
		||||
      __i_am_main_script="1" # true
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    __b3bp_external_usage="true"
 | 
			
		||||
    __b3bp_tmp_source_idx=1
 | 
			
		||||
  fi
 | 
			
		||||
else
 | 
			
		||||
  __i_am_main_script="1" # true
 | 
			
		||||
  [[ "${__usage+x}" ]] && unset -v __usage
 | 
			
		||||
  [[ "${__helptext+x}" ]] && unset -v __helptext
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Set magic variables for current file, directory, os, etc.
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)"
 | 
			
		||||
__file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")"
 | 
			
		||||
__base="$(basename "${__file}" .sh)"
 | 
			
		||||
# shellcheck disable=SC2034,SC2015
 | 
			
		||||
__invocation="$(printf %q "${__file}")$( (($#)) && printf ' %q' "$@" || true)"
 | 
			
		||||
 | 
			
		||||
# Define the environment variables (and their defaults) that this script depends on
 | 
			
		||||
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
 | 
			
		||||
NO_COLOR="${NO_COLOR:-}"    # true = disable color. otherwise autodetected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Functions
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
function __b3bp_log () {
 | 
			
		||||
  local log_level="${1}"
 | 
			
		||||
  shift
 | 
			
		||||
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_debug="\\x1b[35m"
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_info="\\x1b[32m"
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_notice="\\x1b[34m"
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_warning="\\x1b[33m"
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_error="\\x1b[31m"
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_critical="\\x1b[1;31m"
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_alert="\\x1b[1;37;41m"
 | 
			
		||||
  # shellcheck disable=SC2034
 | 
			
		||||
  local color_emergency="\\x1b[1;4;5;37;41m"
 | 
			
		||||
 | 
			
		||||
  local colorvar="color_${log_level}"
 | 
			
		||||
 | 
			
		||||
  local color="${!colorvar:-${color_error}}"
 | 
			
		||||
  local color_reset="\\x1b[0m"
 | 
			
		||||
 | 
			
		||||
  if [[ "${NO_COLOR:-}" = "true" ]] || { [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]]; } || [[ ! -t 2 ]]; then
 | 
			
		||||
    if [[ "${NO_COLOR:-}" != "false" ]]; then
 | 
			
		||||
      # Don't use colors on pipes or non-recognized terminals
 | 
			
		||||
      color=""; color_reset=""
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # all remaining arguments are to be printed
 | 
			
		||||
  local log_line=""
 | 
			
		||||
 | 
			
		||||
  while IFS=$'\n' read -r log_line; do
 | 
			
		||||
    echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%9s]" "${log_level}")${color_reset} ${log_line}" 1>&2
 | 
			
		||||
  done <<< "${@:-}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function emergency () {                                __b3bp_log emergency "${@}"; exit 1; }
 | 
			
		||||
function alert ()     { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __b3bp_log alert "${@}"; true; }
 | 
			
		||||
function critical ()  { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __b3bp_log critical "${@}"; true; }
 | 
			
		||||
function error ()     { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __b3bp_log error "${@}"; true; }
 | 
			
		||||
function warning ()   { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __b3bp_log warning "${@}"; true; }
 | 
			
		||||
function notice ()    { [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __b3bp_log notice "${@}"; true; }
 | 
			
		||||
function info ()      { [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __b3bp_log info "${@}"; true; }
 | 
			
		||||
function debug ()     { [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __b3bp_log debug "${@}"; true; }
 | 
			
		||||
 | 
			
		||||
function help () {
 | 
			
		||||
  echo "" 1>&2
 | 
			
		||||
  echo " ${*}" 1>&2
 | 
			
		||||
  echo "" 1>&2
 | 
			
		||||
  echo "  ${__usage:-No usage available}" 1>&2
 | 
			
		||||
  echo "" 1>&2
 | 
			
		||||
 | 
			
		||||
  if [[ "${__helptext:-}" ]]; then
 | 
			
		||||
    echo " ${__helptext}" 1>&2
 | 
			
		||||
    echo "" 1>&2
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Parse commandline options
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# Commandline options. This defines the usage page, and is used to parse cli
 | 
			
		||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
 | 
			
		||||
# - A short option must be preset for every long option; but every short option
 | 
			
		||||
#   need not have a long option
 | 
			
		||||
# - `--` is respected as the separator between options and arguments
 | 
			
		||||
# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
 | 
			
		||||
#   you can use bash variables to work around this (so use ${HOME} instead)
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2015
 | 
			
		||||
[[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
 | 
			
		||||
  -f --file  [arg] Filename to process. Required.
 | 
			
		||||
  -t --temp  [arg] Location of tempfile. Default="/tmp/bar"
 | 
			
		||||
  -v               Enable verbose mode, print script as it is executed
 | 
			
		||||
  -d --debug       Enables debug mode
 | 
			
		||||
  -h --help        This page
 | 
			
		||||
  -n --no-color    Disable color output
 | 
			
		||||
  -1 --one         Do just one thing
 | 
			
		||||
  -i --input [arg] File to process. Can be repeated.
 | 
			
		||||
  -x               Specify a flag. Can be repeated.
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2015
 | 
			
		||||
[[ "${__helptext+x}" ]] || read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
# Translate usage string -> getopts arguments, and set $arg_<flag> defaults
 | 
			
		||||
while read -r __b3bp_tmp_line; do
 | 
			
		||||
  if [[ "${__b3bp_tmp_line}" =~ ^- ]]; then
 | 
			
		||||
    # fetch single character version of option string
 | 
			
		||||
    __b3bp_tmp_opt="${__b3bp_tmp_line%% *}"
 | 
			
		||||
    __b3bp_tmp_opt="${__b3bp_tmp_opt:1}"
 | 
			
		||||
 | 
			
		||||
    # fetch long version if present
 | 
			
		||||
    __b3bp_tmp_long_opt=""
 | 
			
		||||
 | 
			
		||||
    if [[ "${__b3bp_tmp_line}" = *"--"* ]]; then
 | 
			
		||||
      __b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}"
 | 
			
		||||
      __b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # map opt long name to+from opt short name
 | 
			
		||||
    printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
 | 
			
		||||
    printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}"
 | 
			
		||||
 | 
			
		||||
    # check if option takes an argument
 | 
			
		||||
    if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
 | 
			
		||||
      __b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
 | 
			
		||||
      __b3bp_tmp_init=""  # it has an arg. init with ""
 | 
			
		||||
      printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
 | 
			
		||||
    elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then
 | 
			
		||||
      __b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
 | 
			
		||||
      __b3bp_tmp_init=""  # it has an arg. init with ""
 | 
			
		||||
      # remember that this option requires an argument
 | 
			
		||||
      printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
 | 
			
		||||
    else
 | 
			
		||||
      __b3bp_tmp_init="0" # it's a flag. init with 0
 | 
			
		||||
      printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
 | 
			
		||||
    fi
 | 
			
		||||
    __b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
 | 
			
		||||
 | 
			
		||||
    if [[ "${__b3bp_tmp_line}" =~ ^Can\ be\ repeated\. ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Can\ be\ repeated\. ]]; then
 | 
			
		||||
      # remember that this option can be repeated
 | 
			
		||||
      printf -v "__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" '%s' "1"
 | 
			
		||||
    else
 | 
			
		||||
      printf -v "__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" '%s' "0"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  [[ "${__b3bp_tmp_opt:-}" ]] || continue
 | 
			
		||||
 | 
			
		||||
  if [[ "${__b3bp_tmp_line}" =~ ^Default= ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Default= ]]; then
 | 
			
		||||
    # ignore default value if option does not have an argument
 | 
			
		||||
    __b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
 | 
			
		||||
    if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
 | 
			
		||||
      # take default
 | 
			
		||||
      __b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
 | 
			
		||||
      # strip double quotes from default argument
 | 
			
		||||
      __b3bp_tmp_re='^"(.*)"$'
 | 
			
		||||
      if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
 | 
			
		||||
        __b3bp_tmp_init="${BASH_REMATCH[1]}"
 | 
			
		||||
      else
 | 
			
		||||
        # strip single quotes from default argument
 | 
			
		||||
        __b3bp_tmp_re="^'(.*)'$"
 | 
			
		||||
        if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
 | 
			
		||||
          __b3bp_tmp_init="${BASH_REMATCH[1]}"
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ "${__b3bp_tmp_line}" =~ ^Required\. ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Required\. ]]; then
 | 
			
		||||
    # remember that this option requires an argument
 | 
			
		||||
    printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Init var with value unless it is an array / a repeatable
 | 
			
		||||
  __b3bp_tmp_varname="__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}"
 | 
			
		||||
  [[ "${!__b3bp_tmp_varname}" = "0" ]] && printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
 | 
			
		||||
done <<< "${__usage:-}"
 | 
			
		||||
 | 
			
		||||
# run getopts only if options were specified in __usage
 | 
			
		||||
if [[ "${__b3bp_tmp_opts:-}" ]]; then
 | 
			
		||||
  # Allow long options like --this
 | 
			
		||||
  __b3bp_tmp_opts="${__b3bp_tmp_opts}-:"
 | 
			
		||||
 | 
			
		||||
  # Reset in case getopts has been used previously in the shell.
 | 
			
		||||
  OPTIND=1
 | 
			
		||||
 | 
			
		||||
  # start parsing command line
 | 
			
		||||
  set +o nounset # unexpected arguments will cause unbound variables
 | 
			
		||||
                 # to be dereferenced
 | 
			
		||||
  # Overwrite $arg_<flag> defaults with the actual CLI options
 | 
			
		||||
  while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do
 | 
			
		||||
    [[ "${__b3bp_tmp_opt}" = "?" ]] && help "Invalid use of script: ${*} "
 | 
			
		||||
 | 
			
		||||
    if [[ "${__b3bp_tmp_opt}" = "-" ]]; then
 | 
			
		||||
      # OPTARG is long-option-name or long-option=value
 | 
			
		||||
      if [[ "${OPTARG}" =~ .*=.* ]]; then
 | 
			
		||||
        # --key=value format
 | 
			
		||||
        __b3bp_tmp_long_opt=${OPTARG/=*/}
 | 
			
		||||
        # Set opt to the short option corresponding to the long option
 | 
			
		||||
        __b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
 | 
			
		||||
        printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
 | 
			
		||||
        OPTARG=${OPTARG#*=}
 | 
			
		||||
      else
 | 
			
		||||
        # --key value format
 | 
			
		||||
        # Map long name to short version of option
 | 
			
		||||
        __b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
 | 
			
		||||
        printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
 | 
			
		||||
        # Only assign OPTARG if option takes an argument
 | 
			
		||||
        __b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
 | 
			
		||||
        __b3bp_tmp_varvalue="${!__b3bp_tmp_varname}"
 | 
			
		||||
        [[ "${__b3bp_tmp_varvalue}" != "0" ]] && __b3bp_tmp_varvalue="1"
 | 
			
		||||
        printf -v "OPTARG" '%s' "${@:OPTIND:${__b3bp_tmp_varvalue}}"
 | 
			
		||||
        # shift over the argument if argument is expected
 | 
			
		||||
        ((OPTIND+=__b3bp_tmp_varvalue))
 | 
			
		||||
      fi
 | 
			
		||||
      # we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    __b3bp_tmp_value="${OPTARG}"
 | 
			
		||||
 | 
			
		||||
    __b3bp_tmp_varname="__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}"
 | 
			
		||||
    if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
 | 
			
		||||
      # repeatables
 | 
			
		||||
      # shellcheck disable=SC2016
 | 
			
		||||
      if [[ -z "${OPTARG}" ]]; then
 | 
			
		||||
        # repeatable flags, they increcemnt
 | 
			
		||||
        __b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
 | 
			
		||||
        debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
 | 
			
		||||
          # shellcheck disable=SC2004
 | 
			
		||||
        __b3bp_tmp_value=$((${!__b3bp_tmp_varname} + 1))
 | 
			
		||||
        printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
 | 
			
		||||
      else
 | 
			
		||||
        # repeatable args, they get appended to an array
 | 
			
		||||
        __b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}[@]"
 | 
			
		||||
        debug "cli arg ${__b3bp_tmp_varname} append ${__b3bp_tmp_value}"
 | 
			
		||||
        declare -a "${__b3bp_tmp_varname}"='("${!__b3bp_tmp_varname}" "${__b3bp_tmp_value}")'
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      # non-repeatables
 | 
			
		||||
      __b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
 | 
			
		||||
      __b3bp_tmp_default="${!__b3bp_tmp_varname}"
 | 
			
		||||
 | 
			
		||||
      if [[ -z "${OPTARG}" ]]; then
 | 
			
		||||
        __b3bp_tmp_value=$((__b3bp_tmp_default + 1))
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
 | 
			
		||||
 | 
			
		||||
      debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
  set -o nounset # no more unbound variable references expected
 | 
			
		||||
 | 
			
		||||
  shift $((OPTIND-1))
 | 
			
		||||
 | 
			
		||||
  if [[ "${1:-}" = "--" ]] ; then
 | 
			
		||||
    shift
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Automatic validation of required option arguments
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
 | 
			
		||||
  # validate only options which required an argument
 | 
			
		||||
  [[ "${!__b3bp_tmp_varname}" = "2" ]] || continue
 | 
			
		||||
 | 
			
		||||
  __b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}"
 | 
			
		||||
  __b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}"
 | 
			
		||||
  [[ "${!__b3bp_tmp_varname}" ]] && continue
 | 
			
		||||
 | 
			
		||||
  __b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}"
 | 
			
		||||
  printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}"
 | 
			
		||||
  [[ "${__b3bp_tmp_opt_long:-}" ]] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})"
 | 
			
		||||
 | 
			
		||||
  help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument"
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Cleanup Environment variables
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
for __tmp_varname in ${!__b3bp_tmp_*}; do
 | 
			
		||||
  unset -v "${__tmp_varname}"
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
unset -v __tmp_varname
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Externally supplied __usage. Nothing else to do here
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
 | 
			
		||||
  unset -v __b3bp_external_usage
 | 
			
		||||
  return
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Signal trapping and backtracing
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
function __b3bp_cleanup_before_exit () {
 | 
			
		||||
  info "Cleaning up. Done"
 | 
			
		||||
}
 | 
			
		||||
trap __b3bp_cleanup_before_exit EXIT
 | 
			
		||||
 | 
			
		||||
# requires `set -o errtrace`
 | 
			
		||||
__b3bp_err_report() {
 | 
			
		||||
    local error_code=${?}
 | 
			
		||||
    error "Error in ${__file} in function ${1} on line ${2}"
 | 
			
		||||
    exit ${error_code}
 | 
			
		||||
}
 | 
			
		||||
# Uncomment the following line for always providing an error backtrace
 | 
			
		||||
# trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# debug mode
 | 
			
		||||
if [[ "${arg_d:?}" = "1" ]]; then
 | 
			
		||||
  set -o xtrace
 | 
			
		||||
  PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
 | 
			
		||||
  LOG_LEVEL="7"
 | 
			
		||||
  # Enable error backtracing
 | 
			
		||||
  trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# verbose mode
 | 
			
		||||
if [[ "${arg_v:?}" = "1" ]]; then
 | 
			
		||||
  set -o verbose
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# no color mode
 | 
			
		||||
if [[ "${arg_n:?}" = "1" ]]; then
 | 
			
		||||
  NO_COLOR="true"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# help mode
 | 
			
		||||
if [[ "${arg_h:?}" = "1" ]]; then
 | 
			
		||||
  # Help exists with code 1
 | 
			
		||||
  help "Help using ${0}"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Validation. Error out if the things required for your script are not present
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
[[ "${arg_f:-}" ]]     || help      "Setting a filename with -f or --file is required"
 | 
			
		||||
[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Runtime
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
info "__i_am_main_script: ${__i_am_main_script}"
 | 
			
		||||
info "__file: ${__file}"
 | 
			
		||||
info "__dir: ${__dir}"
 | 
			
		||||
info "__base: ${__base}"
 | 
			
		||||
info "OSTYPE: ${OSTYPE}"
 | 
			
		||||
 | 
			
		||||
info "arg_f: ${arg_f}"
 | 
			
		||||
info "arg_d: ${arg_d}"
 | 
			
		||||
info "arg_v: ${arg_v}"
 | 
			
		||||
info "arg_h: ${arg_h}"
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2015
 | 
			
		||||
if [[ -n "${arg_i:-}" ]] && declare -p arg_i 2> /dev/null | grep -q '^declare \-a'; then
 | 
			
		||||
  info "arg_i:"
 | 
			
		||||
  for input_file in "${arg_i[@]}"; do
 | 
			
		||||
    info " - ${input_file}"
 | 
			
		||||
  done
 | 
			
		||||
elif [[ -n "${arg_i:-}" ]]; then
 | 
			
		||||
  info "arg_i: ${arg_i}"
 | 
			
		||||
else
 | 
			
		||||
  info "arg_i: 0"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2015
 | 
			
		||||
if [[ -n "${arg_x:-}" ]] && declare -p arg_x 2> /dev/null | grep -q '^declare \-a'; then
 | 
			
		||||
  info "arg_x: ${#arg_x[@]}"
 | 
			
		||||
elif [[ -n "${arg_x:-}" ]]; then
 | 
			
		||||
  info "arg_x: ${arg_x}"
 | 
			
		||||
else
 | 
			
		||||
  info "arg_x: 0"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
info "$(echo -e "multiple lines example - line #1\\nmultiple lines example - line #2\\nimagine logging the output of 'ls -al /path/'")"
 | 
			
		||||
 | 
			
		||||
# All of these go to STDERR, so you can use STDOUT for piping machine readable information to other software
 | 
			
		||||
debug "Info useful to developers for debugging the application, not useful during operations."
 | 
			
		||||
info "Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required."
 | 
			
		||||
notice "Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required."
 | 
			
		||||
warning "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time."
 | 
			
		||||
error "Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time."
 | 
			
		||||
critical "Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection."
 | 
			
		||||
alert "Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection."
 | 
			
		||||
emergency "A \"panic\" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call."
 | 
			
		||||
							
								
								
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "bash3boilerplate",
 | 
			
		||||
  "description": "Copypastable templates to write better bash scripts",
 | 
			
		||||
  "version": "2.7.2",
 | 
			
		||||
  "packageManager": "yarn@3.6.0+sha224.19e47520fa56c6146388fdeb438d9dcf6630c3f277a2e1180995c3bb",
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">= 18",
 | 
			
		||||
    "yarn": "3.6.0"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint:shellcheck": "shellcheck --severity=${SHELLCHECK_SEVERITY:-info} $(find . -name '*.sh' -maxdepth 2)",
 | 
			
		||||
    "lint:style": "test/style.pl $(find . -name '*.sh' -maxdepth 2)",
 | 
			
		||||
    "lint": "npm-run-all -l 'lint:**'",
 | 
			
		||||
    "release:major": "env SEMANTIC=major yarn release",
 | 
			
		||||
    "release:minor": "env SEMANTIC=minor yarn release",
 | 
			
		||||
    "release:patch": "env SEMANTIC=patch yarn release",
 | 
			
		||||
    "release": "npm version ${SEMANTIC:-patch} -m \"Release %s\" && yarn version:replace && git commit main.sh src/*.sh -m 'Update version' && git push && git push --tags -f && npm publish",
 | 
			
		||||
    "test:debug:main:repeated": "env LOG_LEVEL=7 test/acceptance.sh main-repeated",
 | 
			
		||||
    "test:update": "env SAVE_FIXTURES=true yarn test",
 | 
			
		||||
    "test": "test/acceptance.sh",
 | 
			
		||||
    "version:current": "node -e 'console.log(require(\"./package.json\").version)'",
 | 
			
		||||
    "version:replace": "replace 'v\\d+\\.\\d+\\.\\d+' \"v$(npm run --silent version:current)\" main.sh src/*.sh"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "fakefile": "1.1.0",
 | 
			
		||||
    "npm-run-all": "4.1.5",
 | 
			
		||||
    "replace": "1.2.2"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										113
									
								
								src/ini_val.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										113
									
								
								src/ini_val.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# BASH3 Boilerplate: ini_val
 | 
			
		||||
#
 | 
			
		||||
# This file:
 | 
			
		||||
#
 | 
			
		||||
#  - Can read and write .ini files using pure bash
 | 
			
		||||
#
 | 
			
		||||
# Limitations:
 | 
			
		||||
#
 | 
			
		||||
#  - All keys inside a section of the .ini file must be unique
 | 
			
		||||
#  - Optional comment parameter for the creation of new entries
 | 
			
		||||
#
 | 
			
		||||
# Usage as a function:
 | 
			
		||||
#
 | 
			
		||||
#  source ini_val.sh
 | 
			
		||||
#  ini_val data.ini connection.host 127.0.0.1 "Host name or IP address"
 | 
			
		||||
#
 | 
			
		||||
# Usage as a command:
 | 
			
		||||
#
 | 
			
		||||
#  ini_val.sh data.ini connection.host 127.0.0.1 "Host name or IP address"
 | 
			
		||||
#
 | 
			
		||||
# Based on a template by BASH3 Boilerplate vv2.7.2
 | 
			
		||||
# http://bash3boilerplate.sh/#authors
 | 
			
		||||
#
 | 
			
		||||
# The MIT License (MIT)
 | 
			
		||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
# as you leave these references intact in the header comments of your source files.
 | 
			
		||||
 | 
			
		||||
function ini_val() {
 | 
			
		||||
  local file="${1:-}"
 | 
			
		||||
  local sectionkey="${2:-}"
 | 
			
		||||
  local val="${3:-}"
 | 
			
		||||
  local comment="${4:-}"
 | 
			
		||||
  local delim="="
 | 
			
		||||
  local comment_delim=";"
 | 
			
		||||
  local section=""
 | 
			
		||||
  local key=""
 | 
			
		||||
  local current=""
 | 
			
		||||
  # add default section
 | 
			
		||||
  local section_default="default"
 | 
			
		||||
 | 
			
		||||
  if [[ ! -f "${file}" ]]; then
 | 
			
		||||
    # touch file if not exists
 | 
			
		||||
    touch "${file}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Split on . for section. However, section is optional
 | 
			
		||||
  IFS='.' read -r section key <<< "${sectionkey}"
 | 
			
		||||
  if [[ ! "${key}" ]]; then
 | 
			
		||||
    key="${section}"
 | 
			
		||||
    # default section if not given
 | 
			
		||||
    section="${section_default}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # get current value (if exists)
 | 
			
		||||
  current=$(sed -En "/^\[/{h;d;};G;s/^${key}([[:blank:]]*)${delim}(.*)\n\[${section}\]$/\2/p" "${file}"|awk '{$1=$1};1')
 | 
			
		||||
  # get current comment (if exists)
 | 
			
		||||
  current_comment=$(sed -En "/^\[${section}\]/,/^\[.*\]/ s|^(${comment_delim}\[${key}\])(.*)|\2|p" "${file}"|awk '{$1=$1};1')
 | 
			
		||||
 | 
			
		||||
  if ! grep -q "\[${section}\]" "${file}"; then
 | 
			
		||||
    # create section if not exists (empty line to seperate new section for better readability)
 | 
			
		||||
    echo  >> "${file}"
 | 
			
		||||
    echo "[${section}]" >> "${file}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ ! "${val}" ]]; then
 | 
			
		||||
    # get a value
 | 
			
		||||
    echo "${current}"
 | 
			
		||||
  else
 | 
			
		||||
    # set a value
 | 
			
		||||
    if [[ ! "${section}" ]]; then
 | 
			
		||||
      # if no section is given, propagate the default section
 | 
			
		||||
      section=${section_default}
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ ! "${comment}" ]]; then
 | 
			
		||||
      # if no comment given, keep old comment
 | 
			
		||||
      comment="${current_comment}"
 | 
			
		||||
    fi
 | 
			
		||||
    # maintenance area
 | 
			
		||||
    # a) remove comment if new given / respect section
 | 
			
		||||
    sed -i.bak "/^\[${section}\]/,/^\[.*\]/ s|^\(${comment_delim}\[${key}\] \).*$||" "${file}"
 | 
			
		||||
    # b) remove old key / respect section
 | 
			
		||||
    sed -i.bak "/^\[${section}\]/,/^\[.*\]/ s|^\(${key}=\).*$||" "${file}"
 | 
			
		||||
    # c) remove all empty lines in ini file
 | 
			
		||||
    sed -i.bak '/^[[:space:]]*$/d' "${file}"
 | 
			
		||||
    # d) insert line break before every section for better readability
 | 
			
		||||
    sed -i.bak $'s/^\\[/\\\n\\[/g' "${file}"
 | 
			
		||||
 | 
			
		||||
    # add to section
 | 
			
		||||
    if [[ ! "${comment}" ]]; then
 | 
			
		||||
      # add new key/value _without_ comment
 | 
			
		||||
      RET="/\\[${section}\\]/a\\
 | 
			
		||||
${key}${delim}${val}"
 | 
			
		||||
    else
 | 
			
		||||
      # add new key/value _with_ preceeding comment
 | 
			
		||||
      RET="/\\[${section}\\]/a\\
 | 
			
		||||
${comment_delim}[${key}] ${comment}\\
 | 
			
		||||
${key}${delim}${val}"
 | 
			
		||||
    fi
 | 
			
		||||
    sed -i.bak -e "${RET}" "${file}"
 | 
			
		||||
    # this .bak dance is done for BSD/GNU portability: http://stackoverflow.com/a/22084103/151666
 | 
			
		||||
    rm -f "${file}.bak"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
 | 
			
		||||
  export -f ini_val
 | 
			
		||||
else
 | 
			
		||||
  ini_val "${@}"
 | 
			
		||||
  exit ${?}
 | 
			
		||||
fi
 | 
			
		||||
							
								
								
									
										78
									
								
								src/megamount.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/megamount.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# BASH3 Boilerplate: megamount
 | 
			
		||||
#
 | 
			
		||||
# This file:
 | 
			
		||||
#
 | 
			
		||||
#  - Takes a URL (smb, nfs, afs) and tries to mount it at a given target directory
 | 
			
		||||
#  - Forcefully unmounts any active mount at the target directory first
 | 
			
		||||
#  - Displays the mount's contents for verification
 | 
			
		||||
#
 | 
			
		||||
# Depends on:
 | 
			
		||||
#
 | 
			
		||||
#  - ./parse_url.sh
 | 
			
		||||
#
 | 
			
		||||
# Usage as a function:
 | 
			
		||||
#
 | 
			
		||||
#  source megamount.sh
 | 
			
		||||
#  megamount smb://janedoe:abc123@192.168.0.1/documents /mnt/documents
 | 
			
		||||
#
 | 
			
		||||
# Usage as a command:
 | 
			
		||||
#
 | 
			
		||||
#  megamount.sh smb://janedoe:abc123@192.168.0.1/documents /mnt/documents
 | 
			
		||||
#
 | 
			
		||||
# Based on a template by BASH3 Boilerplate vv2.7.2
 | 
			
		||||
# http://bash3boilerplate.sh/#authors
 | 
			
		||||
#
 | 
			
		||||
# The MIT License (MIT)
 | 
			
		||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
# as you leave these references intact in the header comments of your source files.
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
 | 
			
		||||
# shellcheck source=src/parse_url.sh
 | 
			
		||||
source "${__dir}/parse_url.sh"
 | 
			
		||||
 | 
			
		||||
function megamount () {
 | 
			
		||||
  local url="${1}"
 | 
			
		||||
  local target="${2}"
 | 
			
		||||
 | 
			
		||||
  local proto
 | 
			
		||||
  local user
 | 
			
		||||
  local pass
 | 
			
		||||
  local host
 | 
			
		||||
  local port
 | 
			
		||||
  local path
 | 
			
		||||
 | 
			
		||||
  proto=$(parse_url "${url}" "proto")
 | 
			
		||||
  user=$(parse_url "${url}" "user")
 | 
			
		||||
  pass=$(parse_url "${url}" "pass")
 | 
			
		||||
  host=$(parse_url "${url}" "host")
 | 
			
		||||
  port=$(parse_url "${url}" "port")
 | 
			
		||||
  path=$(parse_url "${url}" "path")
 | 
			
		||||
 | 
			
		||||
  (umount -lf "${target}" || umount -f "${target}") > /dev/null 2>&1 || true
 | 
			
		||||
  mkdir -p "${target}"
 | 
			
		||||
  if [[ "${proto}" = "smb://" ]]; then
 | 
			
		||||
    mount -t cifs --verbose -o "username=${user},password=${pass},hard" "//${host}/${path}" "${target}"
 | 
			
		||||
  elif [[ "${proto}" = "afp://" ]]; then
 | 
			
		||||
    # start syslog-ng
 | 
			
		||||
    # afpfsd || echo "Unable to run afpfsd. Does /dev/log exist?" && exit 1
 | 
			
		||||
    mount_afp "${url}" "${target}"
 | 
			
		||||
  elif [[ "${proto}" = "nfs://" ]]; then
 | 
			
		||||
    mount -t nfs --verbose -o "vers=3,nolock,soft,intr,rsize=32768,wsize=32768" "${host}:/${path}" "${target}"
 | 
			
		||||
  else
 | 
			
		||||
    echo "ERR: Unknown protocol: '${proto}'"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # chmod 777 "${target}"
 | 
			
		||||
  ls -al "${target}/"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
 | 
			
		||||
  export -f megamount
 | 
			
		||||
else
 | 
			
		||||
  megamount "${@}"
 | 
			
		||||
  exit ${?}
 | 
			
		||||
fi
 | 
			
		||||
							
								
								
									
										84
									
								
								src/parse_url.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/parse_url.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# BASH3 Boilerplate: parse_url
 | 
			
		||||
#
 | 
			
		||||
# This file:
 | 
			
		||||
#
 | 
			
		||||
#  - Takes a URL and parses protocol, user, pass, host, port, path.
 | 
			
		||||
#
 | 
			
		||||
# Based on:
 | 
			
		||||
#
 | 
			
		||||
#  - http://stackoverflow.com/a/6174447/151666
 | 
			
		||||
#
 | 
			
		||||
# Usage as a function:
 | 
			
		||||
#
 | 
			
		||||
#  source parse_url.sh
 | 
			
		||||
#  parse_url 'http://johndoe:abc123@example.com:8080/index.html' pass
 | 
			
		||||
#
 | 
			
		||||
# Usage as a command:
 | 
			
		||||
#
 | 
			
		||||
#  parse_url.sh 'http://johndoe:abc123@example.com:8080/index.html'
 | 
			
		||||
#
 | 
			
		||||
# Based on a template by BASH3 Boilerplate vv2.7.2
 | 
			
		||||
# http://bash3boilerplate.sh/#authors
 | 
			
		||||
#
 | 
			
		||||
# The MIT License (MIT)
 | 
			
		||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
# as you leave these references intact in the header comments of your source files.
 | 
			
		||||
 | 
			
		||||
function parse_url() {
 | 
			
		||||
  local parse="${1}"
 | 
			
		||||
  local need="${2:-}"
 | 
			
		||||
 | 
			
		||||
  local proto
 | 
			
		||||
  local url
 | 
			
		||||
  local userpass
 | 
			
		||||
  local user
 | 
			
		||||
  local pass
 | 
			
		||||
  local hostport
 | 
			
		||||
  local host
 | 
			
		||||
  local port
 | 
			
		||||
  local path
 | 
			
		||||
 | 
			
		||||
  proto="$(echo "${parse}" | grep :// | sed -e's,^\(.*://\).*,\1,g')"
 | 
			
		||||
  url="${parse/${proto}/}"
 | 
			
		||||
  userpass="$(echo "${url}" | grep @ | cut -d@ -f1)"
 | 
			
		||||
  user="$(echo "${userpass}" | grep : | cut -d: -f1)"
 | 
			
		||||
  pass="$(echo "${userpass}" | grep : | cut -d: -f2)"
 | 
			
		||||
  hostport="$(echo "${url/${userpass}@/}" | cut -d/ -f1)"
 | 
			
		||||
  host="$(echo "${hostport}" | grep : | cut -d: -f1)"
 | 
			
		||||
  port="$(echo "${hostport}" | grep : | cut -d: -f2)"
 | 
			
		||||
  path="$(echo "${url}" | grep / | cut -d/ -f2-)"
 | 
			
		||||
 | 
			
		||||
  [[ ! "${user}" ]] && user="${userpass}"
 | 
			
		||||
  [[ ! "${host}" ]] && host="${hostport}"
 | 
			
		||||
  if [[ ! "${port}" ]]; then
 | 
			
		||||
    [[ "${proto}" = "http://" ]]  && port="80"
 | 
			
		||||
    [[ "${proto}" = "https://" ]] && port="443"
 | 
			
		||||
    [[ "${proto}" = "mysql://" ]] && port="3306"
 | 
			
		||||
    [[ "${proto}" = "redis://" ]] && port="6379"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ "${need}" ]]; then
 | 
			
		||||
    echo "${!need}"
 | 
			
		||||
  else
 | 
			
		||||
    echo ""
 | 
			
		||||
    echo " Use second argument to return just 1 variable."
 | 
			
		||||
    echo " parse_url() demo: "
 | 
			
		||||
    echo ""
 | 
			
		||||
    echo "   proto: ${proto}"
 | 
			
		||||
    echo "   user:  ${user}"
 | 
			
		||||
    echo "   pass:  ${pass}"
 | 
			
		||||
    echo "   host:  ${host}"
 | 
			
		||||
    echo "   port:  ${port}"
 | 
			
		||||
    echo "   path:  ${path}"
 | 
			
		||||
    echo ""
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
 | 
			
		||||
  export -f parse_url
 | 
			
		||||
else
 | 
			
		||||
  parse_url "${@}"
 | 
			
		||||
  exit ${?}
 | 
			
		||||
fi
 | 
			
		||||
							
								
								
									
										68
									
								
								src/templater.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								src/templater.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# BASH3 Boilerplate: templater
 | 
			
		||||
#
 | 
			
		||||
# This file:
 | 
			
		||||
#
 | 
			
		||||
#  - takes a source (template) & destination (config) filepath argument
 | 
			
		||||
#  - then replaces placeholders with variables found in the environment
 | 
			
		||||
#
 | 
			
		||||
# Usage as a function:
 | 
			
		||||
#
 | 
			
		||||
#  source templater.sh
 | 
			
		||||
#  export NAME=kevin
 | 
			
		||||
#  templater input.cfg output.cfg
 | 
			
		||||
#
 | 
			
		||||
# Usage as a command:
 | 
			
		||||
#
 | 
			
		||||
#  ALLOW_REMAINDERS=1 templater.sh input.cfg output.cfg
 | 
			
		||||
#
 | 
			
		||||
# Based on a template by BASH3 Boilerplate vv2.7.2
 | 
			
		||||
# http://bash3boilerplate.sh/#authors
 | 
			
		||||
#
 | 
			
		||||
# The MIT License (MIT)
 | 
			
		||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
# as you leave these references intact in the header comments of your source files.
 | 
			
		||||
 | 
			
		||||
function templater() {
 | 
			
		||||
  ALLOW_REMAINDERS="${ALLOW_REMAINDERS:-0}"
 | 
			
		||||
 | 
			
		||||
  templateSrc="${1:-}"
 | 
			
		||||
  templateDst="${2:-}"
 | 
			
		||||
 | 
			
		||||
  if [[ ! -f "${templateSrc}" ]]; then
 | 
			
		||||
    echo "ERROR: Template source '${templateSrc}' needs to exist"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [[ ! "${templateDst}" ]]; then
 | 
			
		||||
    echo "ERROR: Template destination '${templateDst}' needs to be specified"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ "$(command -v perl)" ]]; then
 | 
			
		||||
    perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1} ? $ENV{$1} : "\${$1}")/eg' < "${templateSrc}" > "${templateDst}"
 | 
			
		||||
  else
 | 
			
		||||
    cp -f "${templateSrc}" "${templateDst}"
 | 
			
		||||
 | 
			
		||||
    for var in $(env |awk -F= '{print $1}' |grep -E '^(_[A-Z0-9_]+|[A-Z0-9][A-Z0-9_]*)$'); do
 | 
			
		||||
      sed -i.bak -e "s#\${${var}}#${!var//#/\\#/}#g" "${templateDst}"
 | 
			
		||||
      # this .bak dance is done for BSD/GNU portability: http://stackoverflow.com/a/22084103/151666
 | 
			
		||||
      rm -f "${templateDst}.bak"
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # cat "${templateDst}"
 | 
			
		||||
 | 
			
		||||
  # shellcheck disable=SC2016
 | 
			
		||||
  if grep '${' "${templateDst}" && [[ "${ALLOW_REMAINDERS}" = "0" ]]; then
 | 
			
		||||
    echo "ERROR: Unable to replace the above template vars"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
 | 
			
		||||
  export -f templater
 | 
			
		||||
else
 | 
			
		||||
  templater "${@}"
 | 
			
		||||
  exit ${?}
 | 
			
		||||
fi
 | 
			
		||||
							
								
								
									
										232
									
								
								test/acceptance.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										232
									
								
								test/acceptance.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,232 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# This file:
 | 
			
		||||
#
 | 
			
		||||
#  - Executes one (or all) test scenarios
 | 
			
		||||
#  - Replaces dynamic things like hostnames, IPs, dates, etc
 | 
			
		||||
#  - Optionally saves the results as fixtures, that later runs will be compared against
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
#
 | 
			
		||||
#  ./deploy.sh
 | 
			
		||||
#
 | 
			
		||||
# Based on a template by BASH3 Boilerplate v2.0.0
 | 
			
		||||
# http://bash3boilerplate.sh/#authors
 | 
			
		||||
#
 | 
			
		||||
# The MIT License (MIT)
 | 
			
		||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
 | 
			
		||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
 | 
			
		||||
# as you leave these references intact in the header comments of your source files.
 | 
			
		||||
 | 
			
		||||
# Exit on error. Append || true if you expect an error.
 | 
			
		||||
set -o errexit
 | 
			
		||||
# Exit on error inside any functions or subshells.
 | 
			
		||||
set -o errtrace
 | 
			
		||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
 | 
			
		||||
set -o nounset
 | 
			
		||||
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
 | 
			
		||||
set -o pipefail
 | 
			
		||||
# Turn on traces, useful while debugging but commented out by default
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
# Set magic variables for current file, directory, os, etc.
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
 | 
			
		||||
__base="$(basename "${__file}" .sh)"
 | 
			
		||||
__root="$(cd "$(dirname "${__dir}")" && pwd)"
 | 
			
		||||
 | 
			
		||||
__sysTmpDir="${TMPDIR:-/tmp}"
 | 
			
		||||
__sysTmpDir="${__sysTmpDir%/}" # <-- remove trailing slash on macosx
 | 
			
		||||
__accptstTmpDir=$(mktemp -d "${__sysTmpDir}/${__base}.XXXXXX")
 | 
			
		||||
 | 
			
		||||
function cleanup_before_exit () { rm -r "${__accptstTmpDir:?}"; }
 | 
			
		||||
trap cleanup_before_exit EXIT
 | 
			
		||||
 | 
			
		||||
cmdSed="sed"
 | 
			
		||||
cmdTimeout="timeout"
 | 
			
		||||
 | 
			
		||||
if [[ "${OSTYPE}" = "darwin"* ]]; then
 | 
			
		||||
  cmdSed="gsed"
 | 
			
		||||
  cmdTimeout="gtimeout"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [[ ! "$(command -v ${cmdSed})" ]]; then
 | 
			
		||||
  echo "Please install ${cmdSed}"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [[ ! "$(command -v ${cmdTimeout})" ]]; then
 | 
			
		||||
  echo "Please install ${cmdTimeout}"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
__node="$(command -v node)"
 | 
			
		||||
__arch="amd64"
 | 
			
		||||
 | 
			
		||||
# explicitly setting NO_COLOR to false will make b3bp ignore TERM
 | 
			
		||||
# not being "xterm*" or "screen*" and STDERR not being connected to a terminal
 | 
			
		||||
# it's the opposite of NO_COLOR="true" - it forces color, no matter what
 | 
			
		||||
export NO_COLOR="false"
 | 
			
		||||
 | 
			
		||||
# Running prepare before other scenarios is important on Travis,
 | 
			
		||||
# so that stdio can diverge - and we can enforce stricter
 | 
			
		||||
# stdio comparison on all other tests.
 | 
			
		||||
while IFS=$'\n' read -r scenario; do
 | 
			
		||||
  scenario="$(dirname "${scenario}")"
 | 
			
		||||
  scenario="${scenario##${__dir}/scenario/}"
 | 
			
		||||
 | 
			
		||||
  [[ "${scenario}" = "prepare" ]] && continue
 | 
			
		||||
  [[ "${1:-}" ]] && [[ "${scenario}" != "${1}" ]] && continue
 | 
			
		||||
 | 
			
		||||
  echo "==> Scenario: ${scenario}"
 | 
			
		||||
  pushd "${__dir}/scenario/${scenario}" > /dev/null
 | 
			
		||||
 | 
			
		||||
    # Run scenario
 | 
			
		||||
    (${cmdTimeout} --kill-after=6m 5m bash ./run.sh \
 | 
			
		||||
      > "${__accptstTmpDir}/${scenario}.stdio" 2>&1; \
 | 
			
		||||
      echo "${?}" > "${__accptstTmpDir}/${scenario}.exitcode" \
 | 
			
		||||
    ) || true
 | 
			
		||||
 | 
			
		||||
    # Clear out environmental specifics
 | 
			
		||||
    for typ in stdio exitcode; do
 | 
			
		||||
      curFile="${__accptstTmpDir}/${scenario}.${typ}"
 | 
			
		||||
      "${cmdSed}" -i \
 | 
			
		||||
        -e "s@${__node}@{node}@g" "${curFile}" \
 | 
			
		||||
        -e "s@${__root}@{root}@g" "${curFile}" \
 | 
			
		||||
        -e "s@${__sysTmpDir}@{tmpdir}@g" "${curFile}" \
 | 
			
		||||
        -e "s@/tmp@{tmpdir}@g" "${curFile}" \
 | 
			
		||||
        -e "s@${HOME:-/home/travis}@{home}@g" "${curFile}" \
 | 
			
		||||
        -e "s@${USER:-travis}@{user}@g" "${curFile}" \
 | 
			
		||||
        -e "s@travis@{user}@g" "${curFile}" \
 | 
			
		||||
        -e "s@kvz@{user}@g" "${curFile}" \
 | 
			
		||||
        -e "s@{root}/node_modules/\\.bin/node@{node}@g" "${curFile}" \
 | 
			
		||||
        -e "s@{home}/build/{user}/fre{node}@{node}@g" "${curFile}" \
 | 
			
		||||
        -e "s@${HOSTNAME}@{hostname}@g" "${curFile}" \
 | 
			
		||||
        -e "s@${__arch}@{arch}@g" "${curFile}" \
 | 
			
		||||
        -e "s@${OSTYPE}@{OSTYPE}@g" "${curFile}" \
 | 
			
		||||
        -e "s@OSX@{os}@g" "${curFile}" \
 | 
			
		||||
        -e "s@Linux@{os}@g" "${curFile}" \
 | 
			
		||||
      || false
 | 
			
		||||
 | 
			
		||||
      if grep -q 'ACCPTST:STDIO_REPLACE_IPS' "${curFile}"; then
 | 
			
		||||
        "${cmdSed}" -i \
 | 
			
		||||
          -r 's@[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}@{ip}@g' \
 | 
			
		||||
        "${curFile}"
 | 
			
		||||
 | 
			
		||||
        # IPs vary in length. Ansible uses padding. {ip} does not vary in length
 | 
			
		||||
        # so kill the padding after it for consistent output
 | 
			
		||||
        "${cmdSed}" -i \
 | 
			
		||||
          -r 's@\{ip\}\s+@{ip} @g' \
 | 
			
		||||
        "${curFile}"
 | 
			
		||||
      fi
 | 
			
		||||
      if grep -q 'ACCPTST:STDIO_REPLACE_UUIDS' "${curFile}"; then
 | 
			
		||||
        "${cmdSed}" -i \
 | 
			
		||||
          -r 's@[0-9a-f\-]{32,40}@{uuid}@g' \
 | 
			
		||||
        "${curFile}"
 | 
			
		||||
      fi
 | 
			
		||||
      if grep -q 'ACCPTST:STDIO_REPLACE_BIGINTS' "${curFile}"; then
 | 
			
		||||
        # Such as: 3811298194
 | 
			
		||||
        "${cmdSed}" -i \
 | 
			
		||||
          -r 's@[0-9]{7,64}@{bigint}@g' \
 | 
			
		||||
        "${curFile}"
 | 
			
		||||
      fi
 | 
			
		||||
      if grep -q 'ACCPTST:STDIO_REPLACE_DATETIMES' "${curFile}"; then
 | 
			
		||||
        # Such as: 2016-02-10 15:38:44.420094
 | 
			
		||||
        "${cmdSed}" -i \
 | 
			
		||||
          -r 's@[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}@{datetime}@g' \
 | 
			
		||||
        "${curFile}"
 | 
			
		||||
      fi
 | 
			
		||||
      if grep -q 'ACCPTST:STDIO_REPLACE_LONGTIMES' "${curFile}"; then
 | 
			
		||||
        # Such as: 2016-02-10 15:38:44.420094
 | 
			
		||||
        "${cmdSed}" -i \
 | 
			
		||||
          -r 's@[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{6}@{longtime}@g' \
 | 
			
		||||
        "${curFile}"
 | 
			
		||||
      fi
 | 
			
		||||
      if grep -q 'ACCPTST:STDIO_REPLACE_DURATIONS' "${curFile}"; then
 | 
			
		||||
        # Such as: 0:00:00.001991
 | 
			
		||||
        "${cmdSed}" -i \
 | 
			
		||||
          -r 's@[0-9]{1,2}:[0-9]{2}:[0-9]{2}.[0-9]{6}@{duration}@g' \
 | 
			
		||||
        "${curFile}"
 | 
			
		||||
      fi
 | 
			
		||||
      if grep -q 'ACCPTST:STDIO_REPLACE_REMOTE_EXEC' "${curFile}"; then
 | 
			
		||||
        grep -Ev 'remote-exec\): [ a-zA-Z]' "${curFile}" > "${__sysTmpDir}/accptst-filtered.txt"
 | 
			
		||||
        mv "${__sysTmpDir}/accptst-filtered.txt" "${curFile}"
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    # Save these as new fixtures?
 | 
			
		||||
    if [[ "${SAVE_FIXTURES:-}" = "true" ]]; then
 | 
			
		||||
      for typ in stdio exitcode; do
 | 
			
		||||
        curFile="${__accptstTmpDir}/${scenario}.${typ}"
 | 
			
		||||
        cp -f \
 | 
			
		||||
          "${curFile}" \
 | 
			
		||||
          "${__dir}/fixture/${scenario}.${typ}"
 | 
			
		||||
      done
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Compare
 | 
			
		||||
    for typ in stdio exitcode; do
 | 
			
		||||
      curFile="${__accptstTmpDir}/${scenario}.${typ}"
 | 
			
		||||
 | 
			
		||||
      echo -n "    comparing ${typ}.. "
 | 
			
		||||
 | 
			
		||||
      if [[ "${typ}" = "stdio" ]]; then
 | 
			
		||||
        if grep -q 'ACCPTST:STDIO_SKIP_COMPARE' "${curFile}"; then
 | 
			
		||||
          echo "skip"
 | 
			
		||||
          continue
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if ! diff --strip-trailing-cr "${__dir}/fixture/${scenario}.${typ}" "${curFile}"; then
 | 
			
		||||
        echo -e "\\n\\n==> MISMATCH OF: ${scenario}.${typ} ---^"
 | 
			
		||||
        echo -e "\\n\\n==> EXPECTED STDIO: "
 | 
			
		||||
        cat "${__dir}/fixture/${scenario}.stdio" || true
 | 
			
		||||
        echo -e "\\n\\n==> ACTUAL STDIO: "
 | 
			
		||||
        cat "${__accptstTmpDir}/${scenario}.stdio" || true
 | 
			
		||||
        exit 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      echo "✓"
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
  popd > /dev/null
 | 
			
		||||
done <<< "$(find "${__dir}/scenario" -type f -iname 'run.sh')"
 | 
			
		||||
 | 
			
		||||
[[ "${1:-}" ]] && exit 0
 | 
			
		||||
 | 
			
		||||
# Ensure correct syntax with all available bashes
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC2230
 | 
			
		||||
# "command -v" is not a substitute for "which -a"
 | 
			
		||||
while IFS=$'\n' read -r bash; do
 | 
			
		||||
  if [[ "${bash:-}" = "" ]]; then
 | 
			
		||||
    continue
 | 
			
		||||
  fi
 | 
			
		||||
  # shellcheck disable=SC2016
 | 
			
		||||
  echo "==> ${bash} -n $(${bash} -c 'echo "(${BASH_VERSION})"')"
 | 
			
		||||
  pushd "${__root}" > /dev/null
 | 
			
		||||
 | 
			
		||||
  failed="false"
 | 
			
		||||
 | 
			
		||||
  while IFS=$'\n' read -r file; do
 | 
			
		||||
    [[ "${file}" =~ ^\./node_modules/ ]] && continue
 | 
			
		||||
 | 
			
		||||
    echo -n "    ${file}.. "
 | 
			
		||||
 | 
			
		||||
    if ! "${bash}" -n "${file}" 2>> "${__accptstTmpDir}/${bash//\//.}.err"; then
 | 
			
		||||
      echo "✗"
 | 
			
		||||
      failed="true"
 | 
			
		||||
      continue
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "✓"
 | 
			
		||||
  done <<< "$(find . -type f -iname '*.sh')"
 | 
			
		||||
 | 
			
		||||
  popd > /dev/null
 | 
			
		||||
 | 
			
		||||
  if [[ "${failed}" = "true" ]]; then
 | 
			
		||||
    cat "${__accptstTmpDir}/${bash//\//.}.err"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
done <<< "$(which -a bash 2>/dev/null)"
 | 
			
		||||
 | 
			
		||||
exit 0
 | 
			
		||||
							
								
								
									
										0
									
								
								test/fixture/.empty
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								test/fixture/.empty
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								test/fixture/double-source.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/double-source.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
1
 | 
			
		||||
							
								
								
									
										25
									
								
								test/fixture/double-source.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								test/fixture/double-source.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
{datetime} UTC [35m[    debug][0m cli arg arg_f = () -> {tmpdir}/x
 | 
			
		||||
{datetime} UTC [32m[     info][0m __i_am_main_script: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m __file: {root}/example.sh
 | 
			
		||||
{datetime} UTC [32m[     info][0m __dir: {root}
 | 
			
		||||
{datetime} UTC [32m[     info][0m __base: example
 | 
			
		||||
{datetime} UTC [32m[     info][0m OSTYPE: {OSTYPE}
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_f: {tmpdir}/x
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_d: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_v: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_h: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_i: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_x: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m multiple lines example - line #1
 | 
			
		||||
{datetime} UTC [32m[     info][0m multiple lines example - line #2
 | 
			
		||||
{datetime} UTC [32m[     info][0m imagine logging the output of 'ls -al /path/'
 | 
			
		||||
{datetime} UTC [35m[    debug][0m Info useful to developers for debugging the application, not useful during operations.
 | 
			
		||||
{datetime} UTC [32m[     info][0m Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
 | 
			
		||||
{datetime} UTC [34m[   notice][0m Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
 | 
			
		||||
{datetime} UTC [33m[  warning][0m Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time.
 | 
			
		||||
{datetime} UTC [31m[    error][0m Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
 | 
			
		||||
{datetime} UTC [1;31m[ critical][0m Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
 | 
			
		||||
{datetime} UTC [1;37;41m[    alert][0m Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
 | 
			
		||||
{datetime} UTC [1;4;5;37;41m[emergency][0m A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
 | 
			
		||||
{datetime} UTC [32m[     info][0m Cleaning up. Done
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/ini_val.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/ini_val.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										42
									
								
								test/fixture/ini_val.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								test/fixture/ini_val.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
--> command: Read 3 values
 | 
			
		||||
exists
 | 
			
		||||
127.0.0.1
 | 
			
		||||
nginx, nodejs
 | 
			
		||||
 | 
			
		||||
--> command: Replace three values in-place and show result
 | 
			
		||||
 | 
			
		||||
[default]
 | 
			
		||||
orphan=no more
 | 
			
		||||
 | 
			
		||||
[connection]
 | 
			
		||||
host=192.168.0.1
 | 
			
		||||
 | 
			
		||||
[software]
 | 
			
		||||
packages=vim
 | 
			
		||||
 | 
			
		||||
[comment]
 | 
			
		||||
;[command] got this new comment
 | 
			
		||||
command=works like a chame
 | 
			
		||||
;[new_command] last addition will be moved downwards again after next command
 | 
			
		||||
new_command=commented too
 | 
			
		||||
--> function: Read 3 values
 | 
			
		||||
exists
 | 
			
		||||
127.0.0.1
 | 
			
		||||
nginx, nodejs
 | 
			
		||||
 | 
			
		||||
--> function: Replace three values in-place and show result
 | 
			
		||||
 | 
			
		||||
[default]
 | 
			
		||||
orphan=no more
 | 
			
		||||
 | 
			
		||||
[connection]
 | 
			
		||||
host=192.168.0.1
 | 
			
		||||
 | 
			
		||||
[software]
 | 
			
		||||
packages=vim
 | 
			
		||||
 | 
			
		||||
[comment]
 | 
			
		||||
;[command] got this new comment
 | 
			
		||||
command=works like a chame
 | 
			
		||||
;[new_command] last addition will be moved downwards again after next command
 | 
			
		||||
new_command=commented too
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/main-debug.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/main-debug.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
1
 | 
			
		||||
							
								
								
									
										25
									
								
								test/fixture/main-debug.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								test/fixture/main-debug.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
{datetime} UTC [35m[    debug][0m cli arg arg_f = () -> {tmpdir}/x
 | 
			
		||||
{datetime} UTC [32m[     info][0m __i_am_main_script: 1
 | 
			
		||||
{datetime} UTC [32m[     info][0m __file: {root}/main.sh
 | 
			
		||||
{datetime} UTC [32m[     info][0m __dir: {root}
 | 
			
		||||
{datetime} UTC [32m[     info][0m __base: main
 | 
			
		||||
{datetime} UTC [32m[     info][0m OSTYPE: {OSTYPE}
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_f: {tmpdir}/x
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_d: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_v: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_h: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_i: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_x: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m multiple lines example - line #1
 | 
			
		||||
{datetime} UTC [32m[     info][0m multiple lines example - line #2
 | 
			
		||||
{datetime} UTC [32m[     info][0m imagine logging the output of 'ls -al /path/'
 | 
			
		||||
{datetime} UTC [35m[    debug][0m Info useful to developers for debugging the application, not useful during operations.
 | 
			
		||||
{datetime} UTC [32m[     info][0m Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
 | 
			
		||||
{datetime} UTC [34m[   notice][0m Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
 | 
			
		||||
{datetime} UTC [33m[  warning][0m Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time.
 | 
			
		||||
{datetime} UTC [31m[    error][0m Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
 | 
			
		||||
{datetime} UTC [1;31m[ critical][0m Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
 | 
			
		||||
{datetime} UTC [1;37;41m[    alert][0m Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
 | 
			
		||||
{datetime} UTC [1;4;5;37;41m[emergency][0m A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
 | 
			
		||||
{datetime} UTC [32m[     info][0m Cleaning up. Done
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/main-help.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/main-help.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
1
 | 
			
		||||
							
								
								
									
										19
									
								
								test/fixture/main-help.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/fixture/main-help.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
 | 
			
		||||
 Help using {root}/main.sh
 | 
			
		||||
 | 
			
		||||
  -f --file  [arg] Filename to process. Required.
 | 
			
		||||
  -t --temp  [arg] Location of tempfile. Default="{tmpdir}/bar"
 | 
			
		||||
  -v               Enable verbose mode, print script as it is executed
 | 
			
		||||
  -d --debug       Enables debug mode
 | 
			
		||||
  -h --help        This page
 | 
			
		||||
  -n --no-color    Disable color output
 | 
			
		||||
  -1 --one         Do just one thing
 | 
			
		||||
  -i --input [arg] File to process. Can be repeated.
 | 
			
		||||
  -x               Specify a flag. Can be repeated.
 | 
			
		||||
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
 | 
			
		||||
{datetime} UTC [32m[     info][0m Cleaning up. Done
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/main-longopt.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/main-longopt.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										4
									
								
								test/fixture/main-longopt.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/fixture/main-longopt.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_f: {tmpdir}/x
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_f: {tmpdir}/x
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_f: {tmpdir}/x
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/main-nocolor.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/main-nocolor.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
1
 | 
			
		||||
							
								
								
									
										25
									
								
								test/fixture/main-nocolor.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								test/fixture/main-nocolor.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
{datetime} UTC [    debug] cli arg arg_f = () -> {tmpdir}/x
 | 
			
		||||
{datetime} UTC [     info] __i_am_main_script: 1
 | 
			
		||||
{datetime} UTC [     info] __file: {root}/main.sh
 | 
			
		||||
{datetime} UTC [     info] __dir: {root}
 | 
			
		||||
{datetime} UTC [     info] __base: main
 | 
			
		||||
{datetime} UTC [     info] OSTYPE: {OSTYPE}
 | 
			
		||||
{datetime} UTC [     info] arg_f: {tmpdir}/x
 | 
			
		||||
{datetime} UTC [     info] arg_d: 0
 | 
			
		||||
{datetime} UTC [     info] arg_v: 0
 | 
			
		||||
{datetime} UTC [     info] arg_h: 0
 | 
			
		||||
{datetime} UTC [     info] arg_i: 0
 | 
			
		||||
{datetime} UTC [     info] arg_x: 0
 | 
			
		||||
{datetime} UTC [     info] multiple lines example - line #1
 | 
			
		||||
{datetime} UTC [     info] multiple lines example - line #2
 | 
			
		||||
{datetime} UTC [     info] imagine logging the output of 'ls -al /path/'
 | 
			
		||||
{datetime} UTC [    debug] Info useful to developers for debugging the application, not useful during operations.
 | 
			
		||||
{datetime} UTC [     info] Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
 | 
			
		||||
{datetime} UTC [   notice] Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
 | 
			
		||||
{datetime} UTC [  warning] Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time.
 | 
			
		||||
{datetime} UTC [    error] Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
 | 
			
		||||
{datetime} UTC [ critical] Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
 | 
			
		||||
{datetime} UTC [    alert] Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
 | 
			
		||||
{datetime} UTC [emergency] A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
 | 
			
		||||
{datetime} UTC [     info] Cleaning up. Done
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/main-repeated.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/main-repeated.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										9
									
								
								test/fixture/main-repeated.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								test/fixture/main-repeated.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_i:
 | 
			
		||||
{datetime} UTC [32m[     info][0m  - simple_input
 | 
			
		||||
{datetime} UTC [32m[     info][0m  - input_in_quotes
 | 
			
		||||
{datetime} UTC [32m[     info][0m  - input with spaces
 | 
			
		||||
{datetime} UTC [32m[     info][0m  - input with "quotes"
 | 
			
		||||
{datetime} UTC [32m[     info][0m  - last_input
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_x: 3
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_x: 4
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/main-usage-defaults.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/main-usage-defaults.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										7
									
								
								test/fixture/main-usage-defaults.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/fixture/main-usage-defaults.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_1: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_2: 0
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_3: 'THREE'
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_4: "FOUR"
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_5: OOOPS
 | 
			
		||||
{datetime} UTC [32m[     info][0m arg_6: 
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/main-usage-validation.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/main-usage-validation.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										169
									
								
								test/fixture/main-usage-validation.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								test/fixture/main-usage-validation.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
ACCPTST:STDIO_REPLACE_DATETIMES
 | 
			
		||||
# complain about -3
 | 
			
		||||
 | 
			
		||||
 Option -3 (--three) requires an argument
 | 
			
		||||
 | 
			
		||||
  -0 --zero        Do nothing.
 | 
			
		||||
  -1 --one         Do one thing. Required.
 | 
			
		||||
                   More description.
 | 
			
		||||
  -2 --two         Do two things.
 | 
			
		||||
                   More. Required. Description.
 | 
			
		||||
  -3 --three [arg] Do three things.
 | 
			
		||||
                   Required.
 | 
			
		||||
  -4 --four  {arg} Do four things.
 | 
			
		||||
  -5 --five  {arg} Do five things. Required. Maybe.
 | 
			
		||||
  -6 --six   [arg] Do six things. Not Required.
 | 
			
		||||
                   Required, it is not.
 | 
			
		||||
  -7 --seven [arg] Required. Or bust.
 | 
			
		||||
  -8 --eight [arg] Do eight things.
 | 
			
		||||
                   More.Required.Description.
 | 
			
		||||
  -a         [arg] Do A.   Required.
 | 
			
		||||
                   Default="do-a"
 | 
			
		||||
  -b         {arg} Do B.Default="do-b"
 | 
			
		||||
  -c         [arg] Required.   Default="do-c"
 | 
			
		||||
  -d         {arg} Default="do-d"
 | 
			
		||||
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
 | 
			
		||||
# complain about -4
 | 
			
		||||
 | 
			
		||||
 Option -4 (--four) requires an argument
 | 
			
		||||
 | 
			
		||||
  -0 --zero        Do nothing.
 | 
			
		||||
  -1 --one         Do one thing. Required.
 | 
			
		||||
                   More description.
 | 
			
		||||
  -2 --two         Do two things.
 | 
			
		||||
                   More. Required. Description.
 | 
			
		||||
  -3 --three [arg] Do three things.
 | 
			
		||||
                   Required.
 | 
			
		||||
  -4 --four  {arg} Do four things.
 | 
			
		||||
  -5 --five  {arg} Do five things. Required. Maybe.
 | 
			
		||||
  -6 --six   [arg] Do six things. Not Required.
 | 
			
		||||
                   Required, it is not.
 | 
			
		||||
  -7 --seven [arg] Required. Or bust.
 | 
			
		||||
  -8 --eight [arg] Do eight things.
 | 
			
		||||
                   More.Required.Description.
 | 
			
		||||
  -a         [arg] Do A.   Required.
 | 
			
		||||
                   Default="do-a"
 | 
			
		||||
  -b         {arg} Do B.Default="do-b"
 | 
			
		||||
  -c         [arg] Required.   Default="do-c"
 | 
			
		||||
  -d         {arg} Default="do-d"
 | 
			
		||||
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
 | 
			
		||||
# complain about -5
 | 
			
		||||
 | 
			
		||||
 Option -5 (--five) requires an argument
 | 
			
		||||
 | 
			
		||||
  -0 --zero        Do nothing.
 | 
			
		||||
  -1 --one         Do one thing. Required.
 | 
			
		||||
                   More description.
 | 
			
		||||
  -2 --two         Do two things.
 | 
			
		||||
                   More. Required. Description.
 | 
			
		||||
  -3 --three [arg] Do three things.
 | 
			
		||||
                   Required.
 | 
			
		||||
  -4 --four  {arg} Do four things.
 | 
			
		||||
  -5 --five  {arg} Do five things. Required. Maybe.
 | 
			
		||||
  -6 --six   [arg] Do six things. Not Required.
 | 
			
		||||
                   Required, it is not.
 | 
			
		||||
  -7 --seven [arg] Required. Or bust.
 | 
			
		||||
  -8 --eight [arg] Do eight things.
 | 
			
		||||
                   More.Required.Description.
 | 
			
		||||
  -a         [arg] Do A.   Required.
 | 
			
		||||
                   Default="do-a"
 | 
			
		||||
  -b         {arg} Do B.Default="do-b"
 | 
			
		||||
  -c         [arg] Required.   Default="do-c"
 | 
			
		||||
  -d         {arg} Default="do-d"
 | 
			
		||||
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
 | 
			
		||||
# complain about -8 (because -7 syntax is not supported)
 | 
			
		||||
 | 
			
		||||
 Option -8 (--eight) requires an argument
 | 
			
		||||
 | 
			
		||||
  -0 --zero        Do nothing.
 | 
			
		||||
  -1 --one         Do one thing. Required.
 | 
			
		||||
                   More description.
 | 
			
		||||
  -2 --two         Do two things.
 | 
			
		||||
                   More. Required. Description.
 | 
			
		||||
  -3 --three [arg] Do three things.
 | 
			
		||||
                   Required.
 | 
			
		||||
  -4 --four  {arg} Do four things.
 | 
			
		||||
  -5 --five  {arg} Do five things. Required. Maybe.
 | 
			
		||||
  -6 --six   [arg] Do six things. Not Required.
 | 
			
		||||
                   Required, it is not.
 | 
			
		||||
  -7 --seven [arg] Required. Or bust.
 | 
			
		||||
  -8 --eight [arg] Do eight things.
 | 
			
		||||
                   More.Required.Description.
 | 
			
		||||
  -a         [arg] Do A.   Required.
 | 
			
		||||
                   Default="do-a"
 | 
			
		||||
  -b         {arg} Do B.Default="do-b"
 | 
			
		||||
  -c         [arg] Required.   Default="do-c"
 | 
			
		||||
  -d         {arg} Default="do-d"
 | 
			
		||||
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
 | 
			
		||||
# complain about -d (because -d syntax is not supported)
 | 
			
		||||
 | 
			
		||||
 Option -d requires an argument
 | 
			
		||||
 | 
			
		||||
  -0 --zero        Do nothing.
 | 
			
		||||
  -1 --one         Do one thing. Required.
 | 
			
		||||
                   More description.
 | 
			
		||||
  -2 --two         Do two things.
 | 
			
		||||
                   More. Required. Description.
 | 
			
		||||
  -3 --three [arg] Do three things.
 | 
			
		||||
                   Required.
 | 
			
		||||
  -4 --four  {arg} Do four things.
 | 
			
		||||
  -5 --five  {arg} Do five things. Required. Maybe.
 | 
			
		||||
  -6 --six   [arg] Do six things. Not Required.
 | 
			
		||||
                   Required, it is not.
 | 
			
		||||
  -7 --seven [arg] Required. Or bust.
 | 
			
		||||
  -8 --eight [arg] Do eight things.
 | 
			
		||||
                   More.Required.Description.
 | 
			
		||||
  -a         [arg] Do A.   Required.
 | 
			
		||||
                   Default="do-a"
 | 
			
		||||
  -b         {arg} Do B.Default="do-b"
 | 
			
		||||
  -c         [arg] Required.   Default="do-c"
 | 
			
		||||
  -d         {arg} Default="do-d"
 | 
			
		||||
 | 
			
		||||
 This is Bash3 Boilerplate's help text. Feel free to add any description of your
 | 
			
		||||
 program or elaborate more on command-line arguments. This section is not
 | 
			
		||||
 parsed and will be added as-is to the help.
 | 
			
		||||
 | 
			
		||||
# complain about nothing
 | 
			
		||||
{datetime} UTC [     info] arg_0: 0
 | 
			
		||||
{datetime} UTC [     info] arg_1: 0
 | 
			
		||||
{datetime} UTC [     info] arg_2: 0
 | 
			
		||||
{datetime} UTC [     info] arg_3: arg3
 | 
			
		||||
{datetime} UTC [     info] arg_4: arg4
 | 
			
		||||
{datetime} UTC [     info] arg_5: arg5
 | 
			
		||||
{datetime} UTC [     info] arg_6: 
 | 
			
		||||
{datetime} UTC [     info] arg_7: 
 | 
			
		||||
{datetime} UTC [     info] arg_8: arg8
 | 
			
		||||
{datetime} UTC [     info] arg_a: do-a
 | 
			
		||||
{datetime} UTC [     info] arg_b: do-b
 | 
			
		||||
{datetime} UTC [     info] arg_c: do-c
 | 
			
		||||
{datetime} UTC [     info] arg_d: argd
 | 
			
		||||
# test for issue #108
 | 
			
		||||
{datetime} UTC [     info] arg_0: 1
 | 
			
		||||
{datetime} UTC [     info] arg_1: 0
 | 
			
		||||
{datetime} UTC [     info] arg_2: 0
 | 
			
		||||
{datetime} UTC [     info] arg_3: arg3
 | 
			
		||||
{datetime} UTC [     info] arg_4: value
 | 
			
		||||
{datetime} UTC [     info] arg_5: arg5
 | 
			
		||||
{datetime} UTC [     info] arg_6: 
 | 
			
		||||
{datetime} UTC [     info] arg_7: 
 | 
			
		||||
{datetime} UTC [     info] arg_8: arg8
 | 
			
		||||
{datetime} UTC [     info] arg_a: do-a
 | 
			
		||||
{datetime} UTC [     info] arg_b: do-b
 | 
			
		||||
{datetime} UTC [     info] arg_c: do-c
 | 
			
		||||
{datetime} UTC [     info] arg_d: argd
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/megamount.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/megamount.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
1
 | 
			
		||||
							
								
								
									
										2
									
								
								test/fixture/megamount.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								test/fixture/megamount.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
ERR: Unknown protocol: 'foobarfs://'
 | 
			
		||||
ERR: Unknown protocol: 'foobarfs://'
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/parse_url.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/parse_url.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
0
 | 
			
		||||
							
								
								
									
										24
									
								
								test/fixture/parse_url.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								test/fixture/parse_url.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
abc123
 | 
			
		||||
 | 
			
		||||
 Use second argument to return just 1 variable.
 | 
			
		||||
 parse_url() demo: 
 | 
			
		||||
 | 
			
		||||
   proto: http://
 | 
			
		||||
   user:  johndoe
 | 
			
		||||
   pass:  abc123
 | 
			
		||||
   host:  example.com
 | 
			
		||||
   port:  8080
 | 
			
		||||
   path:  index.html
 | 
			
		||||
 | 
			
		||||
abc123
 | 
			
		||||
 | 
			
		||||
 Use second argument to return just 1 variable.
 | 
			
		||||
 parse_url() demo: 
 | 
			
		||||
 | 
			
		||||
   proto: http://
 | 
			
		||||
   user:  johndoe
 | 
			
		||||
   pass:  abc123
 | 
			
		||||
   host:  example.com
 | 
			
		||||
   port:  8080
 | 
			
		||||
   path:  index.html
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								test/fixture/templater.exitcode
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/fixture/templater.exitcode
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
1
 | 
			
		||||
							
								
								
									
										14
									
								
								test/fixture/templater.stdio
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								test/fixture/templater.stdio
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
--
 | 
			
		||||
[connection]
 | 
			
		||||
host = 127.0.0.1
 | 
			
		||||
--
 | 
			
		||||
[connection]
 | 
			
		||||
host = 127.0.0.1
 | 
			
		||||
--
 | 
			
		||||
port = ${I_DONT_EXIST}
 | 
			
		||||
[connection]
 | 
			
		||||
host = 127.0.0.1
 | 
			
		||||
port = ${I_DONT_EXIST}
 | 
			
		||||
--
 | 
			
		||||
port = ${I_DONT_EXIST}
 | 
			
		||||
ERROR: Unable to replace the above template vars
 | 
			
		||||
							
								
								
									
										15
									
								
								test/scenario/double-source/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								test/scenario/double-source/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
export LOG_LEVEL=7
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
# shellcheck source=example.sh
 | 
			
		||||
source "${__root}/example.sh" -f /tmp/x
 | 
			
		||||
							
								
								
									
										8
									
								
								test/scenario/ini_val/data.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								test/scenario/ini_val/data.ini
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
[default]
 | 
			
		||||
orphan=exists
 | 
			
		||||
 | 
			
		||||
[connection]
 | 
			
		||||
host=127.0.0.1
 | 
			
		||||
 | 
			
		||||
[software]
 | 
			
		||||
packages=nginx, nodejs
 | 
			
		||||
							
								
								
									
										54
									
								
								test/scenario/ini_val/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										54
									
								
								test/scenario/ini_val/run.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
# Set magic variables for current FILE & DIR
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
# echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Use as standalone:
 | 
			
		||||
cp -f data.ini dummy.ini
 | 
			
		||||
echo "--> command: Read 3 values"
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini orphan
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini connection.host
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini software.packages
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.command
 | 
			
		||||
 | 
			
		||||
echo "--> command: Replace three values in-place and show result"
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini orphan "no more"
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini connection.host "192.168.0.1"
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini software.packages "vim"
 | 
			
		||||
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.command "commented" "this key is commented"
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.new_command "commented too" "last addition will be moved downwards again after next command"
 | 
			
		||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.command "works like a chame" "got this new comment"
 | 
			
		||||
cat dummy.ini
 | 
			
		||||
rm -f dummy.ini
 | 
			
		||||
 | 
			
		||||
# Use as include:
 | 
			
		||||
cp -f data.ini dummy.ini
 | 
			
		||||
 | 
			
		||||
# shellcheck source=main.sh
 | 
			
		||||
source "${__root}/src/ini_val.sh"
 | 
			
		||||
 | 
			
		||||
echo "--> function: Read 3 values"
 | 
			
		||||
ini_val ./dummy.ini orphan
 | 
			
		||||
ini_val ./dummy.ini connection.host
 | 
			
		||||
ini_val ./dummy.ini software.packages
 | 
			
		||||
ini_val ./dummy.ini comment.command
 | 
			
		||||
 | 
			
		||||
echo "--> function: Replace three values in-place and show result"
 | 
			
		||||
ini_val ./dummy.ini orphan "no more"
 | 
			
		||||
ini_val ./dummy.ini connection.host "192.168.0.1"
 | 
			
		||||
ini_val ./dummy.ini software.packages "vim"
 | 
			
		||||
 | 
			
		||||
ini_val ./dummy.ini comment.command "commented" "this key is commited"
 | 
			
		||||
ini_val ./dummy.ini comment.new_command "commented too" "last addition will be moved downwards again after next command"
 | 
			
		||||
ini_val ./dummy.ini comment.command "works like a chame" "got this new comment"
 | 
			
		||||
cat dummy.ini
 | 
			
		||||
rm -f dummy.ini
 | 
			
		||||
							
								
								
									
										12
									
								
								test/scenario/main-debug/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/scenario/main-debug/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
env LOG_LEVEL=7 bash "${__root}/main.sh" -f /tmp/x
 | 
			
		||||
							
								
								
									
										12
									
								
								test/scenario/main-help/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								test/scenario/main-help/run.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
bash "${__root}/main.sh" -f /tmp/x -h
 | 
			
		||||
							
								
								
									
										16
									
								
								test/scenario/main-longopt/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/scenario/main-longopt/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# set -o pipefail
 | 
			
		||||
# set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
(
 | 
			
		||||
  env LOG_LEVEL=6 bash "${__root}/main.sh" --file /tmp/x;
 | 
			
		||||
  env LOG_LEVEL=6 bash "${__root}/main.sh" --file=/tmp/x;
 | 
			
		||||
  env LOG_LEVEL=6 bash "${__root}/main.sh" -f /tmp/x
 | 
			
		||||
) 2>&1 |grep arg_f
 | 
			
		||||
							
								
								
									
										12
									
								
								test/scenario/main-nocolor/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/scenario/main-nocolor/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
env LOG_LEVEL=7 NO_COLOR=true bash "${__root}/main.sh" -f /tmp/x
 | 
			
		||||
							
								
								
									
										19
									
								
								test/scenario/main-repeated/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/scenario/main-repeated/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# set -o pipefail
 | 
			
		||||
# set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
(
 | 
			
		||||
  env LOG_LEVEL="${LOG_LEVEL:-6}" bash "${__root}/main.sh" -f dummy -i simple_input -i "input_in_quotes" -i "input with spaces" -i "input with \"quotes\"" -i last_input
 | 
			
		||||
) 2>&1 |grep arg_i -A 5
 | 
			
		||||
 | 
			
		||||
(
 | 
			
		||||
  env LOG_LEVEL="${LOG_LEVEL:-6}" bash "${__root}/main.sh" -x -f dummy -x -x
 | 
			
		||||
  env LOG_LEVEL="${LOG_LEVEL:-6}" bash "${__root}/main.sh" -f dummy -xxxx
 | 
			
		||||
) 2>&1 |grep arg_x
 | 
			
		||||
							
								
								
									
										32
									
								
								test/scenario/main-usage-defaults/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								test/scenario/main-usage-defaults/run.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
 | 
			
		||||
  -1 --one         Do one thing. Default="ONE"
 | 
			
		||||
                   More description.
 | 
			
		||||
  -2 --two         Do two things.
 | 
			
		||||
                   More description. Default="TWO"
 | 
			
		||||
  -3 --three [arg] Do three things. Default="'THREE'"
 | 
			
		||||
                   More description.
 | 
			
		||||
  -4 --four  [arg] Do four things.
 | 
			
		||||
                   More description. Default='"FOUR"'
 | 
			
		||||
  -5 --five  [arg] Do five things. Default="FIVE"
 | 
			
		||||
                   More description. Default='OOOPS'
 | 
			
		||||
  -6 --six   [arg] Do six things.
 | 
			
		||||
                   More description.
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
export __usage
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
# shellcheck source=main.sh
 | 
			
		||||
source "${__root}/main.sh"
 | 
			
		||||
 | 
			
		||||
for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
 | 
			
		||||
							
								
								
									
										64
									
								
								test/scenario/main-usage-validation/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										64
									
								
								test/scenario/main-usage-validation/run.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# shellcheck source=main.sh
 | 
			
		||||
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
 | 
			
		||||
  -0 --zero        Do nothing.
 | 
			
		||||
  -1 --one         Do one thing. Required.
 | 
			
		||||
                   More description.
 | 
			
		||||
  -2 --two         Do two things.
 | 
			
		||||
                   More. Required. Description.
 | 
			
		||||
  -3 --three [arg] Do three things.
 | 
			
		||||
                   Required.
 | 
			
		||||
  -4 --four  {arg} Do four things.
 | 
			
		||||
  -5 --five  {arg} Do five things. Required. Maybe.
 | 
			
		||||
  -6 --six   [arg] Do six things. Not Required.
 | 
			
		||||
                   Required, it is not.
 | 
			
		||||
  -7 --seven [arg] Required. Or bust.
 | 
			
		||||
  -8 --eight [arg] Do eight things.
 | 
			
		||||
                   More.Required.Description.
 | 
			
		||||
  -a         [arg] Do A.   Required.
 | 
			
		||||
                   Default="do-a"
 | 
			
		||||
  -b         {arg} Do B.Default="do-b"
 | 
			
		||||
  -c         [arg] Required.   Default="do-c"
 | 
			
		||||
  -d         {arg} Default="do-d"
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
export __usage
 | 
			
		||||
export NO_COLOR="true"
 | 
			
		||||
 | 
			
		||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
 | 
			
		||||
 | 
			
		||||
echo "# complain about -3"
 | 
			
		||||
(source "${__root}/main.sh") || true
 | 
			
		||||
 | 
			
		||||
echo "# complain about -4"
 | 
			
		||||
(source "${__root}/main.sh" -3 arg3) || true
 | 
			
		||||
 | 
			
		||||
echo "# complain about -5"
 | 
			
		||||
(source "${__root}/main.sh" -3 arg3 -4 arg4) || true
 | 
			
		||||
 | 
			
		||||
echo "# complain about -8 (because -7 syntax is not supported)"
 | 
			
		||||
(source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5) || true
 | 
			
		||||
 | 
			
		||||
echo "# complain about -d (because -d syntax is not supported)"
 | 
			
		||||
(source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5 -8 arg8) || true
 | 
			
		||||
 | 
			
		||||
echo "# complain about nothing"
 | 
			
		||||
(
 | 
			
		||||
  source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5 -8 arg8 -d argd
 | 
			
		||||
  for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
echo "# test for issue #108"
 | 
			
		||||
(
 | 
			
		||||
  source "${__root}/main.sh" -3 arg3 -5 arg5 -8 arg8 -d argd --four value --zero
 | 
			
		||||
  for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										21
									
								
								test/scenario/megamount/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								test/scenario/megamount/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
__sysTmpDir="${TMPDIR:-/tmp}"
 | 
			
		||||
__sysTmpDir="${__sysTmpDir%/}" # <-- remove trailing slash on macosx
 | 
			
		||||
 | 
			
		||||
# Currently I only know how to test a failing condition here since
 | 
			
		||||
# it's too invasive to create actual mounts to play with on a system
 | 
			
		||||
 | 
			
		||||
bash "${__root}/src/megamount.sh" 'foobarfs://janedoe:abc123@192.168.0.1/documents' "${__sysTmpDir}/mnt/documents" || true
 | 
			
		||||
 | 
			
		||||
# shellcheck source=src/megamount.sh
 | 
			
		||||
source "${__root}/src/megamount.sh"
 | 
			
		||||
 | 
			
		||||
megamount 'foobarfs://janedoe:abc123@192.168.0.1/documents' "${__sysTmpDir}/mnt/documents"
 | 
			
		||||
							
								
								
									
										17
									
								
								test/scenario/parse_url/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								test/scenario/parse_url/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
bash "${__root}/src/parse_url.sh" 'http://johndoe:abc123@example.com:8080/index.html' pass
 | 
			
		||||
bash "${__root}/src/parse_url.sh" 'http://johndoe:abc123@example.com:8080/index.html'
 | 
			
		||||
 | 
			
		||||
# shellcheck source=src/parse_url.sh
 | 
			
		||||
source "${__root}/src/parse_url.sh"
 | 
			
		||||
 | 
			
		||||
parse_url 'http://johndoe:abc123@example.com:8080/index.html' pass
 | 
			
		||||
parse_url 'http://johndoe:abc123@example.com:8080/index.html'
 | 
			
		||||
							
								
								
									
										2
									
								
								test/scenario/templater/app.template.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								test/scenario/templater/app.template.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
[connection]
 | 
			
		||||
host = ${TARGET_HOST}
 | 
			
		||||
							
								
								
									
										3
									
								
								test/scenario/templater/break.template.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								test/scenario/templater/break.template.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
[connection]
 | 
			
		||||
host = ${TARGET_HOST}
 | 
			
		||||
port = ${I_DONT_EXIST}
 | 
			
		||||
							
								
								
									
										36
									
								
								test/scenario/templater/run.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								test/scenario/templater/run.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
set -o pipefail
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
# set -o xtrace
 | 
			
		||||
 | 
			
		||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | 
			
		||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
 | 
			
		||||
__base="$(basename "${__file}" .sh)"
 | 
			
		||||
 | 
			
		||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
 | 
			
		||||
 | 
			
		||||
__templaterTmpFile=$(mktemp "${TMPDIR:-/tmp}/${__base}.XXXXXX")
 | 
			
		||||
function cleanup_before_exit () { rm "${__templaterTmpFile:?}"; }
 | 
			
		||||
trap cleanup_before_exit EXIT
 | 
			
		||||
 | 
			
		||||
echo "--"
 | 
			
		||||
env TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./app.template.cfg "${__templaterTmpFile}"
 | 
			
		||||
cat "${__templaterTmpFile}"
 | 
			
		||||
 | 
			
		||||
echo "--"
 | 
			
		||||
export TARGET_HOST="127.0.0.1"
 | 
			
		||||
 | 
			
		||||
# shellcheck source=src/templater.sh
 | 
			
		||||
source "${__root}/src/templater.sh"
 | 
			
		||||
 | 
			
		||||
templater ./app.template.cfg "${__templaterTmpFile}"
 | 
			
		||||
cat "${__templaterTmpFile}"
 | 
			
		||||
 | 
			
		||||
echo "--"
 | 
			
		||||
env ALLOW_REMAINDERS="1" TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./break.template.cfg "${__templaterTmpFile}"
 | 
			
		||||
cat "${__templaterTmpFile}"
 | 
			
		||||
 | 
			
		||||
echo "--"
 | 
			
		||||
env TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./break.template.cfg "${__templaterTmpFile}"
 | 
			
		||||
cat "${__templaterTmpFile}"
 | 
			
		||||
							
								
								
									
										45
									
								
								test/style.pl
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										45
									
								
								test/style.pl
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
#!/usr/bin/env perl
 | 
			
		||||
 | 
			
		||||
use strict;
 | 
			
		||||
use warnings;
 | 
			
		||||
 | 
			
		||||
die "usage: $0 <file>\n" if (not @ARGV);
 | 
			
		||||
 | 
			
		||||
my $rc = 0;
 | 
			
		||||
my $file = shift;
 | 
			
		||||
 | 
			
		||||
open(my $fh, '<', $file) or die "Cannot open \`$file' for read: $!\n";
 | 
			
		||||
while (<$fh>) {
 | 
			
		||||
  next if (/^\s*#/);
 | 
			
		||||
 | 
			
		||||
  my $errors = 0;
 | 
			
		||||
 | 
			
		||||
  # remove everything between single quotes
 | 
			
		||||
  # this will remove too much in case of: echo "var='$var'"
 | 
			
		||||
  # and thus miss an opportunity to complain later on
 | 
			
		||||
  # also it mangles the input line irreversible
 | 
			
		||||
  s/'[^']+'/'___'/g;
 | 
			
		||||
 | 
			
		||||
  # highlight unbraced variables--
 | 
			
		||||
  # unless properly backslash'ed
 | 
			
		||||
  $errors += s/((?:^|[^\\]))(((\\\\)+)?\$\w)/$1\033[31m$2\033[0m/g;
 | 
			
		||||
 | 
			
		||||
  # highlight single square brackets
 | 
			
		||||
  $errors += s/((?:^|\s+))\[([^\[].+[^\]])\](\s*(;|&&|\|\|))/$1\033[31m\[\033[0m$2\033[31m\]\033[0m$3/g;
 | 
			
		||||
 | 
			
		||||
  # highlight double equal sign
 | 
			
		||||
  $errors += s/(\[\[.*)(==)(.*\]\])/$1\033[31m$2\033[0m$3/g;
 | 
			
		||||
 | 
			
		||||
  # highlight tabs mixed with whitespace at beginning of lines
 | 
			
		||||
  $errors += s/^( *)(\t+ *)/\033[31m\[$2\]\033[0m/;
 | 
			
		||||
 | 
			
		||||
  # highlight trailing whitespace
 | 
			
		||||
  $errors += s/([ \t]+)$/\033[31m\[$1\]\033[0m/;
 | 
			
		||||
 | 
			
		||||
  next if (not $errors);
 | 
			
		||||
  print "${file}[$.]: $_";
 | 
			
		||||
  $rc = 1;
 | 
			
		||||
}
 | 
			
		||||
close($fh);
 | 
			
		||||
 | 
			
		||||
exit $rc;
 | 
			
		||||
		Reference in New Issue
	
	Block a user