BAUX is a bash auxiliary library for writing script.
- ๐จ Features
- ๐ Prerequisite
- ๐ Installation
- ๐ Usage
- ๐บ Contributing
- ๐ฆ Authors
- ๐ License
- Helper: Basic script writing helper functions, such as getting script's name, version and help message, importing other script once, warning or exit when get a wrong status. (
baux.sh) - Assertion: Functions for writing reliable APIs, ensuring the pre- or post-condition. (
ensure.sh) - Utility: Useful utility functions for getting options, reading a simple config file, printing message with color and so on. (
utils.sh) - Debugging: Simple functions for logging (
log.sh) and print callstack when failed (trace.sh). - Testing: Functions for check a variable (
var.sh) and writing unit tests (test.sh). - Exception: (Not yet finished)
try(),catch(),throw().
- Array: Functions for array manipulation. (
array.sh)- Data structure: stack, queue.
- Sort and search:
sort(),bsearch().
- Pattern: POSIX compatible characters patterns and other common regex. (
pattern.sh)- Pattern match: IP, URL, tele-number, etc.
ispattern check.
You can get this program with git:
$ git clone https://github.com/ishbguy/baux
lib
โโโ array.sh # array manipulate functions
โโโ baux.sh # basic helper functions
โโโ pattern.sh # POSIX compatible characters patterns and other common regex
โโโ ensure.sh # assertion functions
โโโ except.sh # not yet finished
โโโ log.sh # simple logging
โโโ test.sh # unit test functions
โโโ trace.sh # simple callstack function
โโโ utils.sh # useful tools
โโโ var.sh # checking variablesexcept.sh
|-----------------------------------------------+
V |
array.sh test.sh |
| |-----------------------------------|
V V V
var.sh utils.sh pattern.sh log.sh trace.sh
| | | | |
+-----------+-----------+-----------+-----------+
V
baux.sh <-> ensure.shAs the Library Dependence Diagram above, you can easily source one of the library file to include the functions you need, for example:
# in your script
source /path/to/baux/lib/baux.sh
[[ -e $file ]] || die "$file not exist."# your script
source /path/to/baux/lib/baux.sh
[[ -e $opt_file ]] || warn "Just warn you that $opt_file does not exsit"
[[ -e $need_file ]] || die "$need_file not found! This will exit with $BAUX_EXIT_CODE"
echo "Can not be here."PS: Though warn runs successfully, it does return ((++BAUX_EXIT_CODE)) in the end, so warn returns an none-zero when it finished!
#! /usr/bin/env bash
# your script
source /path/to/baux/lib/baux.sh
echo "The script name is $(proname)" # will print the script name
VERSION="v0.0.1" # need to define VERSION first, or version will warn
echo "The script version is $(version)" # will print the script version
HELP="This is a help message." # need to define HELP first, or usage will warn
usage # print help messagePS: usage call version first to print version message, then print help message, so, both VERSION and HELP should be predefined when call usage.
baux.sh includes an import function to ensure source a file for only one time.
source /path/to/baux/lib/baux.sh
import /path/to/your/lib.sh # this will import once
import /path/to/your/lib.sh # OK, but will not import lib.sh again
cmd_from_lib_sh
import /file/not/exsit.sh # this will fail, and make you script die
echo "Can not be here!"Assertion functions are useful for writing APIs, and they can be sorted in 3 catogories: general, explicit and implicit assertion.
ensure can make an assertion with a given expression, if the expression is true, it will continue to run the following commands, or it will die and print a given message.
source /path/to/baux/lib/ensure.sh
# the first arg is expression, the second arg is error message, which is optional
NUM=1
ensure "$NUM == 1" "$NUM must be equal 1" # OK
ensure "2 -gt $NUM" "2 must greater than $NUM" # OK
ensure "$NUM == 1.0" "$NUM must be 1.0" # this will die, for $NUM act as string '1' not '1.0'The expression given to ensure will be eval [[ $expr ]] inside ensure.
ensure_not_empty can test all given args wheather they are not empty, if anyone of them is empty, it will die.
source /path/to/baux/lib/ensure.sh
one=1
two=2
empty=
ensure_not_empty "$one" "$two" # OK
ensure_not_empty "$empty" # will die
echo "Can not be here."It is a best practice to wrap each arg with double qoute.
ensure_is "$1" "$2" is equivalent to ensure "$1 == $2".
source /path/to/baux/lib/ensure.sh
one=1
ensure_is "$one" "1" "$one is not 1" # OK
ensure_is "$one" "1.0" "$one is not 1" # will die
echo "Can not be here."ensure_isnt "$1" "$2" is equivalent to ensure "$1 != $2".
source /path/to/baux/lib/ensure.sh
one=1
ensure_isnt "$one" "1.0" "$one is not 1" # OK
ensure_isnt "$one" "1" "$one is not 1" # will die
echo "Can not be here."ensure_like "$1" "$2" is equivalent to ensure "$1 =~ $2"
source /path/to/baux/lib/ensure.sh
str="This is a test"
ensure_like "$str" "a" "$str does not like a" # OK
ensure_like "$str" "test" "$str does not like test" # OK
ensure_like "$str" "check" "$str does not like check" # will die
echo "Can not be here."ensure_unlike "$1" "$2" is equivalent to ensure "! $1 =~ $2"
source /path/to/baux/lib/ensure.sh
str="This is a test"
ensure_unlike "$str" "TEST" "$str like TEST" # OK
ensure_unlike "$str" "IS" "$str like IS" # OK
ensure_unlike "$str" "test" "$str like test" # will die
echo "Can not be here."The BAUX_ENSURE_DEBUG variable act as a switch to turn on or off the assertion, its default value is 1, which means turn on assertion, if you want to turn off, you can set BAUX_ENSURE_DEBUG to 0 before sourcing the ensure.sh.
source /path/to/baux/lib/utils.sh
# need to declare two associative arrays
# one for options and one for arguments
declare -A opts args
# The first arg is array NAME for options
# The second arg is array NAME for arguments
# The third arg is the options string, a letter for an option,
# letter follow with ':' means a option argument
# The remain args are needed to be parsed
getoptions opts args "n:vh" "$@"
# after getoptions, need to correct the option index
shift $((OPTIND - 1))
# now you can check options and arguments
[[ ${opts[h]} -eq 1 ]] && echo "Option 'h' invoke"
[[ ${opts[v]} -eq 1 ]] && echo "Option 'v' invoke"
[[ ${opts[n]} -eq 1 ]] && echo "Option 'n' invoke, argument is ${args[n]}"
# an invoked option will be assigned with 1
# an invoked option with an argument, the argument value will be storedsource /path/to/baux/lib/utils.sh
# need to declare an associative array for storing config value
declare -A CONFIGS
# config name and value are seperated with '='
# strings follow '#' means comment
# each line allows one name-value pair
# leading and tailing spaces is allowed
# spaces on both sides of '=' is allowed, too
echo "NAME=ishbguy" >>my.config
echo "[email protected]" >>my.config
read_config CONFIGS my.config
# you will notice that all config name will convert to lower case
echo "my name is ${CONFIGS[name]}"
echo "my email is ${CONFIGS[email]}"
read_config CONFIGS file-not-exsit # will not fail, just return 1source /path/to/baux/lib/utils.sh
cecho red "This message will print in red" # color can be: black, red, green
# yellow, blue, magenta, cyan, white
realdir /path/to/script # similar to realpath, this will print /path/to
realdir /p1/script1 /p2/script2 # will print /p1 /p2
check_tool sed awk realpath # check needed tools in PATH
check_tool tools-not-exsit # will dieBAUX has a simple log function which can accept a log level and message string args, then print the log mesages to stdout or a specified log file.
BAUX also has a simple callstack function to print out the call stack when encountering error.
source /path/to/baux/lib/log.sh
# log has 5 log level and priority from low to high is:
#
# debug < info < warn < error < fatal < panic < quiet
#
# default log output level is debug, means that the log priority higher than
# debug will be printed.
log debug "This is a log test" # this will print a log message to stdout
BAUX_LOG_OUTPUT_LEVEL=info # set log output level to info
log debug "a debug message" # will not print
log info "a info message" # will print into stdout
# set a log output file, default is empty which will print into stdout
# if test.log is not exsit, log will create it
BAUX_LOG_OUTPUT_FILE=test.log
log info "write into a log file" # this will write into test.logsource /path/to/baux/lib/trace.sh
# callstack need a start index of the function stack array
# if index is 0, which will print also the callstack 0, if index is 1,
# which will not print callstack line, and start to print from function
# three.
one() {
two
}
two() {
three
}
three() {
callstack 0
}
oneRun the above test script, will print the callstack to stdout like:
+ callstack 0 [./test.sh:16:three]
+ three [./test.sh:13:two]
+ two [./test.sh:10:one]
+ one [./test.sh:19:main]source /path/to/baux/lib/var.sh
declare -a var
type_array var && echo "this is an index array"
type_map var && echo "this is an associative array"
type_int var && echo "this is an integer var"
type_func var && echo "this is a function name"
type_ref var && echo "this is a var reference"
type_export var && echo "this is an exported var"
type_lower var && echo "var's value has lower case attribute"
type_upper var && echo "var's value has upper case attribute"BAUX's test functions are similar to Perl's Test::More module.
source /path/to/baux/lib/test.sh
# ok $expr test is equivalent to [[ $expr ]]
ok '1 == 1' 'Test equal' # pass
ok '1 != 0' 'Test not equal' # pass
# is $a $b test is equivalent to [[ $a == $b ]]
is 1 1 "Test equal" # pass
is 1 0 "Test not equal" # fail
# isnt $a $b test is equivalent to [[ $a != $b ]]
isnt 1 1 "Test equal" # fail
isnt 1 0 "Test not equal" # pass
# like $a $b test is equivalent to [[ $a =~ $b ]]
like "apple" "app" "Test like" # pass
like "apple" "App" "Test not like" # fail
# unlike $a $b test is equivalent to [[ ! $a =~ $b ]]
unlike "apple" "app" "Test like" # fail
unlike "apple" "App" "Test not like" # pass
# each test status will print when that test finish
# finally, report a summary with the numbers of:
# total, pass, fail and skip
summarysource /path/to/baux/lib/test.sh
# run_ok like ok, but run_ok provide $status, $output inside to test the
# exit status and cmd output. When use these 2 variables, you need to single
# quote the expr to avoid expanded outside run_ok. And the given cmd is run
# in a subshell like output=$(eval "$cmd" 2>&1), you can check both nomral
# and error message in $output.
run_ok '$status -eq 0' exit 0 # pass
run_ok '$status -eq 1' exit 1 # pass
run_ok '$output =~ "command not found"' cmd_not_found # pass
run_ok '$output =~ "hello world"' echo "hello world" # pass
# you can also do like this for the test statement inside run_ok is equivalent
# to [[ $expr ]]
run_ok '$status -eq 0 && $(echo $output | wc -l) -eq 1' echo "test" # pass
summarysubtest will group the your tests in a single sub-test, if one of the tests in subtest fails, the subtest will fail, and the total and fail counters will increase 1.
source /path/to/baux/lib/test.sh
# format like: subtest "test name" 'tests cmds'
subtest 'subtest PASS' "
is 1 1 'test equal'
isnt 1 0 'test not equal'
"
summarysource /path/to/baux/lib/test.sh
is 1 1 # pass
skip
isnt 1 1 # this will skip
isnt 0 1 # this will run and pass
summaryYou can customize test's total, pass, fail, skip prompt strings and colors.
source /path/to/baux/lib/test.sh
# these are default prompt strings
BAUX_TEST_PROMPTS[TOTAL]="TOTAL"
BAUX_TEST_PROMPTS[PASS]="PASS"
BAUX_TEST_PROMPTS[FAIL]="FAIL"
BAUX_TEST_PROMPTS[SKIP]="SKIP"
# these are default colors, you can change color which cecho accept
BAUX_TEST_COLORS[TOTAL]="blue"
BAUX_TEST_COLORS[PASS]="green"
BAUX_TEST_COLORS[FAIL]="red"
BAUX_TEST_COLORS[SKIP]="yellow"
BAUX_TEST_COLORS[EMSG]="red"- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request
Released under the terms of MIT License.