Skip to content
/ baux Public

BAUX is a bash auxiliary library for writing script.

License

Notifications You must be signed in to change notification settings

ishbguy/baux

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Travis Codecov Codacy Version License

BAUX is a bash auxiliary library for writing script.

Table of Contents

๐ŸŽจ Features

  • 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.
    • is pattern check.

๐Ÿ“ Prerequisite

๐Ÿš€ Installation

You can get this program with git:

$ git clone https://github.com/ishbguy/baux

๐Ÿ““ Usage

Library Hierarchy

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 variables

Library Dependence Diagram

except.sh
    |-----------------------------------------------+
    V                                               |
array.sh    test.sh                                 |
    |           |-----------------------------------|
    V           V                                   V
var.sh      utils.sh    pattern.sh    log.sh      trace.sh
    |           |           |           |           |
    +-----------+-----------+-----------+-----------+
    V
baux.sh <-> ensure.sh

How to Use BAUX Library?

As 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."

Helper Functions (baux.sh)

Warning

# 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!

Information

#! /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 message

PS: usage call version first to print version message, then print help message, so, both VERSION and HELP should be predefined when call usage.

Importation

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 (ensure.sh)

Assertion functions are useful for writing APIs, and they can be sorted in 3 catogories: general, explicit and implicit assertion.

General 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.

Explicit Assertion

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."

Implicit Assertion

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."

Assertion Switch

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.

Utility (utils.sh)

Get Options

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 stored

Read Config File

source /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=ishbguy@hotmail.com" >>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 1

Other Utilities

source /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 die

Debugging (log.sh, trace.sh)

BAUX 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.

Logging (log.sh)

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.log

Callstack (trace.sh)

source /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
}

one

Run 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]

Testing (var.sh, test.sh)

Variable Type Check (var.sh)

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"

Unit Test (test.sh)

BAUX's test functions are similar to Perl's Test::More module.

Simple test
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
summary
Run command test with run_ok
source /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

summary
Run subtest

subtest 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'
"

summary
skip a following test
source /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

summary
Customize test outputs

You 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"

Exception (except.sh)

Array (array.sh)

Pattern (pattern.sh)

๐ŸŒบ Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

๐Ÿ‘ฆ Authors

๐Ÿ“œ License

Released under the terms of MIT License.

Releases

No releases published

Packages

No packages published