├── _is_integer.sh ├── _is_empty.sh ├── _is_positive_integer.sh ├── _inform.sh ├── _verify_dependencies.sh ├── _error.sh ├── _warn.sh ├── _print_args.sh ├── _is_blank.sh ├── _get_file_extension.sh ├── _get_file_name.sh ├── _time_convert_s_to_hhmmss.sh ├── _get_file_name_without_extension.sh ├── _repeat.sh ├── _get_file_directory.sh ├── _get_file_path.sh ├── _urlencode.sh ├── _die.sh ├── _get_directory_path.sh ├── _trim.sh ├── _transliterate.sh ├── _join.sh ├── _find_nearest_integer.sh ├── templates ├── _library_function.sh └── script ├── _send_sms_msg.sh ├── _generate_password.sh ├── _is_apache_vhost.sh ├── _send_mail_msg.sh ├── _verify_arg_count.sh ├── autoload.sh ├── examples ├── session-info └── _introduce.sh ├── docs ├── error-handling.md ├── makedoc ├── coding-standards.md └── function-list.md ├── README.md ├── _lorem.sh ├── .gitattributes ├── LICENSE ├── _declare_ansi_escape_sequences.sh └── test └── test /_is_integer.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::is_integer(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Determines if the argument is an integer. 11 | # 12 | # @param string $value_to_test 13 | # The value to be tested. 14 | # 15 | # @example 16 | # bfl::is_integer "8675309" 17 | #------------------------------------------------------------------------------ 18 | # 19 | bfl::is_integer() { 20 | bfl::verify_arg_count "$#" 1 1 || exit 1 21 | 22 | declare -r argument="$1" 23 | declare -r regex="^-{0,1}[0-9]+$" 24 | 25 | if ! [[ "${argument}" =~ ${regex} ]] ; then 26 | return 1 27 | fi 28 | } 29 | -------------------------------------------------------------------------------- /_is_empty.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::is_empty(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Checks if a string is empty ("") or null. 11 | # 12 | # @param string $str 13 | # The string to check. 14 | # 15 | # @example 16 | # bfl::is_empty "foo" 17 | #------------------------------------------------------------------------------ 18 | bfl::is_empty() { 19 | # Verify argument count. 20 | bfl::verify_arg_count "$#" 1 1 || exit 1 21 | 22 | # Declare positional arguments (readonly, sorted by position). 23 | declare -r str="$1" 24 | 25 | # Check the string. 26 | [[ -z "${str}" ]] || return 1 27 | } 28 | -------------------------------------------------------------------------------- /_is_positive_integer.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::is_positive_integer(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Determines if the argument is a positive integer. 11 | # 12 | # @param string $value_to_test 13 | # The value to be tested. 14 | # 15 | # @example 16 | # bfl::is_positive_integer "8675309" 17 | #------------------------------------------------------------------------------ 18 | bfl::is_positive_integer() { 19 | bfl::verify_arg_count "$#" 1 1 || exit 1 20 | 21 | declare -r argument="$1" 22 | declare -r regex="^[1-9][0-9]*$" 23 | 24 | if ! [[ "${argument}" =~ ${regex} ]] ; then 25 | return 1 26 | fi 27 | } 28 | -------------------------------------------------------------------------------- /_inform.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::inform(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Prints an informational message to stderr. 11 | # 12 | # @param string $msg (optional) 13 | # The message. A blank line will be printed if no message is provided. 14 | # 15 | # @example 16 | # bfl::inform "The foo is bar." 17 | # 18 | # shellcheck disable=SC2154 19 | #------------------------------------------------------------------------------ 20 | bfl::inform() { 21 | # Verify argument count. 22 | bfl::verify_arg_count "$#" 0 1 || exit 1 23 | 24 | # Declare positional arguments (readonly, sorted by position). 25 | declare msg="${1:-}" 26 | 27 | # Print the message. 28 | printf "%b\\n" "${msg}" 1>&2 29 | } 30 | -------------------------------------------------------------------------------- /_verify_dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::verify_dependencies(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Verifies that dependencies are installed. 11 | # 12 | # @param array $apps 13 | # One dimensional array of applications, executables, or commands. 14 | # 15 | # @example 16 | # bfl::verify_dependencies "curl" "wget" "git" 17 | #------------------------------------------------------------------------------ 18 | bfl::verify_dependencies() { 19 | bfl::verify_arg_count "$#" 1 999 || exit 1 20 | 21 | declare -ar apps=("$@") 22 | declare app 23 | 24 | for app in "${apps[@]}"; do 25 | if ! hash "${app}" 2> /dev/null; then 26 | bfl::die "${app} is not installed." 27 | fi 28 | done 29 | } 30 | -------------------------------------------------------------------------------- /_error.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::error(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Prints an error message to stderr. 11 | # 12 | # The message provided will be prepended with "Error. " 13 | # 14 | # @param string $msg (optional) 15 | # The message. 16 | # 17 | # @example 18 | # bfl::error "The foo is bar." 19 | # 20 | # shellcheck disable=SC2154 21 | #------------------------------------------------------------------------------ 22 | bfl::error() { 23 | # Verify argument count. 24 | bfl::verify_arg_count "$#" 0 1 || exit 1 25 | 26 | # Declare positional arguments (readonly, sorted by position). 27 | declare msg="${1:-"Unspecified error."}" 28 | 29 | # Print the message. 30 | printf "%b\\n" "${bfl_aes_red}Error. ${msg}${bfl_aes_reset}" 1>&2 31 | } 32 | -------------------------------------------------------------------------------- /_warn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::warn(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Prints a warning message to stderr. 11 | # 12 | # The message provided will be prepended with "Warning. " 13 | # 14 | # @param string $msg (optional) 15 | # The message. 16 | # 17 | # @example 18 | # bfl::warn "The foo is bar." 19 | # 20 | # shellcheck disable=SC2154 21 | #------------------------------------------------------------------------------ 22 | bfl::warn() { 23 | # Verify argument count. 24 | bfl::verify_arg_count "$#" 0 1 || exit 1 25 | 26 | # Declare positional arguments (readonly, sorted by position). 27 | declare msg="${1:-"Unspecified warning."}" 28 | 29 | # Print the message. 30 | printf "%b\\n" "${bfl_aes_yellow}Warning. ${msg}${bfl_aes_reset}" 1>&2 31 | } 32 | -------------------------------------------------------------------------------- /_print_args.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::print_args(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Prints the arguments passed to this function. 11 | # 12 | # A debugging tool. Accepts between 1 and 999 arguments. 13 | # 14 | # @param list $arguments 15 | # One or more arguments. 16 | # 17 | # @example 18 | # bfl::print_args "foo" "bar" "baz" 19 | #------------------------------------------------------------------------------ 20 | bfl::print_args() { 21 | bfl::verify_arg_count "$#" 1 999 || exit 1 22 | 23 | declare -ar args=("$@") 24 | declare counter=0 25 | declare arg 26 | 27 | printf "===== Begin output from %s =====\\n" "${FUNCNAME[0]}" 28 | for arg in "${args[@]}"; do 29 | ((counter++)) || true 30 | printf "$%s = %s\\n" "${counter}" "${arg}" 31 | done 32 | printf "===== End output from %s =====\\n" "${FUNCNAME[0]}" 33 | } 34 | -------------------------------------------------------------------------------- /_is_blank.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::is_blank(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Checks if a string is whitespace, empty (""), or null. 11 | # 12 | # Backslash escape sequences are interpreted prior to evaluation. Whitespace 13 | # characters include space, horizontal tab (\t), new line (\n), vertical 14 | # tab (\v), form feed (\f), and carriage return (\r). 15 | # 16 | # @param string $str 17 | # The string to check. 18 | # 19 | # @example 20 | # bfl::is_blank "foo" 21 | #------------------------------------------------------------------------------ 22 | bfl::is_blank() { 23 | # Verify argument count. 24 | bfl::verify_arg_count "$#" 1 1 || exit 1 25 | 26 | # Declare positional arguments (readonly, sorted by position). 27 | declare -r str="$1" 28 | 29 | # Check the string. 30 | [[ "$(printf "%b" "${str}")" =~ ^[[:space:]]*$ ]] || return 1 31 | } 32 | -------------------------------------------------------------------------------- /_get_file_extension.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::get_file_extension(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Gets the file extension. 11 | # 12 | # @param string $path 13 | # A relative path, absolute path, or symbolic link. 14 | # 15 | # @return string $file_extension 16 | # The file extension, excluding the preceding period. 17 | # 18 | # @example 19 | # bfl::get_file_extension "./foo/bar.txt" 20 | #------------------------------------------------------------------------------ 21 | bfl::get_file_extension() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | 24 | declare -r path="$1" 25 | declare file_name 26 | declare file_extension 27 | 28 | if bfl::is_empty "${path}"; then 29 | bfl::die "The path was not specified." 30 | fi 31 | 32 | file_name="$(bfl::get_file_name "$1")" || bfl::die 33 | file_extension="${file_name##*.}" 34 | 35 | printf "%s" "${file_extension}" 36 | } 37 | -------------------------------------------------------------------------------- /_get_file_name.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::get_file_name(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Gets the file name, including extension. 11 | # 12 | # @param string $path 13 | # A relative path, absolute path, or symbolic link. 14 | # 15 | # @return string $file_name 16 | # The file name, including extension. 17 | # 18 | # @example 19 | # bfl::get_file_name "./foo/bar.text" 20 | #------------------------------------------------------------------------------ 21 | bfl::get_file_name() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | 24 | declare -r path="$1" 25 | declare canonical_file_path 26 | declare file_name 27 | 28 | if bfl::is_empty "${path}"; then 29 | bfl::die "The path was not specified." 30 | fi 31 | 32 | canonical_file_path=$(bfl::get_file_path "${path}") || bfl::die 33 | file_name=$(basename "${canonical_file_path}") || bfl::die 34 | 35 | printf "%s" "${file_name}" 36 | } 37 | -------------------------------------------------------------------------------- /_time_convert_s_to_hhmmss.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::time_convert_s_to_hhmmss(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Converts seconds to the hh:mm:ss format. 11 | # 12 | # @param int $seconds 13 | # The number of seconds to convert. 14 | # 15 | # @return string $hhmmss 16 | # The number of seconds in hh:mm:ss format. 17 | # 18 | # @example 19 | # bfl::time_convert_s_to_hhmmss "3661" 20 | #------------------------------------------------------------------------------ 21 | bfl::time_convert_s_to_hhmmss() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | 24 | declare -r seconds="$1" 25 | declare hhmmss 26 | 27 | bfl::is_positive_integer "${seconds}" \ 28 | || bfl::die "Expected positive integer, received ${seconds}." 29 | 30 | hhmmss=$(printf '%02d:%02d:%02d\n' \ 31 | $((seconds/3600)) \ 32 | $((seconds%3600/60)) \ 33 | $((seconds%60))) \ 34 | || bfl::die "Unable to convert ${seconds} to hh:mm:ss format." 35 | 36 | printf "%s" "${hhmmss}" 37 | } 38 | -------------------------------------------------------------------------------- /_get_file_name_without_extension.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::get_file_name_without_extension(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Gets the file name, excluding extension. 11 | # 12 | # @param string $path 13 | # A relative path, absolute path, or symbolic link. 14 | # 15 | # @return string $file_name_without_extension 16 | # The file name, excluding extension. 17 | # 18 | # @example 19 | # bfl::get_file_name_without_extension "./foo/bar.txt" 20 | #------------------------------------------------------------------------------ 21 | bfl::get_file_name_without_extension() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | 24 | declare -r path="$1" 25 | declare file_name 26 | declare file_name_without_extension 27 | 28 | if bfl::is_empty "${path}"; then 29 | bfl::die "The path was not specified." 30 | fi 31 | 32 | file_name="$(bfl::get_file_name "$1")" || bfl::die 33 | file_name_without_extension="${file_name%.*}" 34 | 35 | printf "%s" "${file_name_without_extension}" 36 | } 37 | -------------------------------------------------------------------------------- /_repeat.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::repeat(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Repeats a string. 11 | # 12 | # @param string $str 13 | # The string to be repeated. 14 | # @param int $multiplier 15 | # Number of times the string will be repeated. 16 | # 17 | # @return string $str_repeated 18 | # The repeated string. 19 | # 20 | # @example 21 | # bfl::repeat "=" "10" 22 | #------------------------------------------------------------------------------ 23 | bfl::repeat() { 24 | bfl::verify_arg_count "$#" 2 2 || exit 1 25 | 26 | declare -r str="$1" 27 | declare -r multiplier="$2" 28 | declare str_repeated 29 | 30 | bfl::is_positive_integer "${multiplier}" \ 31 | || bfl::die "Expected positive integer, received ${multiplier}." 32 | 33 | # Create a string of spaces that is $multiplier long. 34 | str_repeated=$(printf "%${multiplier}s") || bfl::die 35 | # Replace each space with the $str. 36 | str_repeated=${str_repeated// /"${str}"} 37 | 38 | printf "%s" "${str_repeated}" 39 | } 40 | -------------------------------------------------------------------------------- /_get_file_directory.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::get_file_directory(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Gets the canonical path to the directory in which a file resides. 11 | # 12 | # @param string $path 13 | # A relative path, absolute path, or symbolic link. 14 | # 15 | # @return string $canonical_directory_path 16 | # The canonical path to the directory in which a file resides. 17 | # 18 | # @example 19 | # bfl::get_file_directory "./foo/bar.txt" 20 | #------------------------------------------------------------------------------ 21 | bfl::get_file_directory() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | 24 | declare -r path="$1" 25 | declare canonical_directory_path 26 | declare canonical_file_path 27 | 28 | if bfl::is_empty "${path}"; then 29 | bfl::die "The path was not specified." 30 | fi 31 | 32 | canonical_file_path=$(bfl::get_file_path "${path}") || bfl::die 33 | canonical_directory_path=$(dirname "${canonical_file_path}}") || bfl::die 34 | 35 | printf "%s" "${canonical_directory_path}" 36 | } 37 | -------------------------------------------------------------------------------- /_get_file_path.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::get_file_path(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Gets the canonical path to a file. 11 | # 12 | # @param string $path 13 | # A relative path, absolute path, or symbolic link. 14 | # 15 | # @return string $canonical_file_path 16 | # The canonical path to the file. 17 | # 18 | # @example 19 | # bfl::get_file_path "./foo/bar.text" 20 | #------------------------------------------------------------------------------ 21 | bfl::get_file_path() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | 24 | declare -r path="$1" 25 | declare canonical_file_path 26 | 27 | if bfl::is_empty "${path}"; then 28 | bfl::die "The path was not specified." 29 | fi 30 | 31 | # Verify that the path exists. 32 | if ! canonical_file_path=$(readlink -e "${path}"); then 33 | bfl::die "${path} does not exist." 34 | fi 35 | 36 | # Verify that the path points to a file, not a directory. 37 | if [[ ! -f "${canonical_file_path}" ]]; then 38 | bfl::die "${canonical_file_path} is not a file." 39 | fi 40 | 41 | printf "%s" "${canonical_file_path}" 42 | } 43 | -------------------------------------------------------------------------------- /_urlencode.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::urlencode(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Percent-encodes a URL. 11 | # 12 | # See . 13 | # 14 | # @param string $str 15 | # The string to be encoded. 16 | # 17 | # @return string $str_encoded 18 | # The encoded string. 19 | # 20 | # @example 21 | # bfl::urlencode "foo bar" 22 | #------------------------------------------------------------------------------ 23 | bfl::urlencode() { 24 | # Verify argument count. 25 | bfl::verify_arg_count "$#" 1 1 || exit 1 26 | 27 | # Verify dependencies. 28 | bfl::verify_dependencies "jq" 29 | 30 | # Declare positional arguments (readonly, sorted by position). 31 | declare -r str="$1" 32 | 33 | # Declare return value. 34 | declare str_encoded 35 | 36 | # Verify argument values. 37 | bfl::is_empty "$str" && bfl::die "Empty string." 38 | 39 | # Build the return value. 40 | str_encoded=$(jq -Rr @uri <<< "${str}") \ 41 | || bfl::die "Unable to URL encode the string." 42 | 43 | # Print the return value. 44 | printf "%s\\n" "${str_encoded}" 45 | } 46 | -------------------------------------------------------------------------------- /_die.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::die(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Prints a fatal error message to stderr, then exits with status code 1. 11 | # 12 | # The message provided will be prepended with "Fatal error. " 13 | # 14 | # @param string $msg (optional) 15 | # The message. 16 | # 17 | # @example 18 | # bfl::error "The foo is bar." 19 | # 20 | # shellcheck disable=SC2154 21 | #------------------------------------------------------------------------------ 22 | bfl::die() { 23 | # Verify argument count. 24 | bfl::verify_arg_count "$#" 0 1 || exit 1 25 | 26 | # Declare positional arguments (readonly, sorted by position). 27 | declare -r msg="${1:-"Unspecified fatal error."}" 28 | 29 | # Declare all other variables (sorted by name). 30 | declare stack 31 | 32 | # Build a string showing the "stack" of functions that got us here. 33 | stack="${FUNCNAME[*]}" 34 | stack="${stack// / <- }" 35 | 36 | # Print the message. 37 | printf "%b\\n" "${bfl_aes_red}Fatal error. ${msg}${bfl_aes_reset}" 1>&2 38 | 39 | # Print the stack. 40 | printf "%b\\n" "${bfl_aes_yellow}[${stack}]${bfl_aes_reset}" 1>&2 41 | 42 | exit 1 43 | } 44 | -------------------------------------------------------------------------------- /_get_directory_path.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::get_directory_path(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Gets the canonical path to a directory. 11 | # 12 | # @param string $path 13 | # A relative path, absolute path, or symbolic link. 14 | # 15 | # @return string $canonical_directory_path 16 | # The canonical path to the directory. 17 | # 18 | # @example 19 | # bfl::get_directory_path "./foo" 20 | #------------------------------------------------------------------------------ 21 | bfl::get_directory_path() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | 24 | declare -r path="$1" 25 | declare canonical_directory_path 26 | 27 | if bfl::is_empty "${path}"; then 28 | bfl::die "The path was not specified." 29 | fi 30 | 31 | # Verify that the path exists. 32 | if ! canonical_directory_path=$(readlink -e "${path}"); then 33 | bfl::die "${path} does not exist." 34 | fi 35 | 36 | # Verify that the path points to a directory, not a file. 37 | if [[ ! -d "${canonical_directory_path}" ]]; then 38 | bfl::die "${canonical_directory_path} is not a directory." 39 | fi 40 | 41 | printf "%s" "${canonical_directory_path}" 42 | } 43 | -------------------------------------------------------------------------------- /_trim.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::trim(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Removes leading and trailing whitespace, including blank lines, from string. 11 | # 12 | # The string can either be single or multi-line. In a multi-line string, 13 | # leading and trailing whitespace is removed from every line. 14 | # 15 | # @param string $str 16 | # The string to be trimmed. 17 | # 18 | # @return string $str_trimmed 19 | # The trimmed string. 20 | # 21 | # @example 22 | # bfl::trim " foo " 23 | #------------------------------------------------------------------------------ 24 | bfl::trim() { 25 | bfl::verify_arg_count "$#" 1 1 || exit 1 26 | 27 | declare -r str="$1" 28 | declare str_trimmed 29 | 30 | # Explanation of sed commands: 31 | # - Remove leading whitespace from every line: s/^[[:space:]]+// 32 | # - Remove trailing whitespace from every line: s/[[:space:]]+$// 33 | # - Remove leading and trailing blank lines: /./,$ !d 34 | # 35 | # See https://tinyurl.com/yav7zw9k and https://tinyurl.com/3z8eh 36 | 37 | str_trimmed=$(printf "%b" "${str}" | \ 38 | sed -E 's/^[[:space:]]+// ; s/[[:space:]]+$// ; /./,$ !d') \ 39 | || bfl::die "Unable to trim whitespace." 40 | 41 | printf "%s" "${str_trimmed}" 42 | } 43 | -------------------------------------------------------------------------------- /_transliterate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::transliterate(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Transliterates a string. 11 | # 12 | # @param string $str 13 | # The string to transliterate. 14 | # 15 | # @return string $str_transliterated 16 | # The transliterated string. 17 | # 18 | # @example 19 | # bfl::transliterate "_Olé Über! " 20 | #------------------------------------------------------------------------------ 21 | bfl::transliterate() { 22 | bfl::verify_arg_count "$#" 1 1 || exit 1 23 | bfl::verify_dependencies "iconv" 24 | 25 | declare -r str="$1" 26 | declare str_transliterated 27 | 28 | # Enable extended pattern matching features. 29 | shopt -s extglob 30 | 31 | # Convert from UTF-8 to ASCII. 32 | str_transliterated=$(iconv -c -f utf8 -t ascii//TRANSLIT <<< "${str}") || bfl::die 33 | # Replace non-alphanumeric characters with a hyphen. 34 | str_transliterated=${str_transliterated//[^[:alnum:]]/-} 35 | # Replace two or more sequential hyphens with a single hyphen. 36 | str_transliterated=${str_transliterated//+(-)/-} 37 | # Remove leading hyphen, if any. 38 | str_transliterated=${str_transliterated#-} 39 | # Remove trailing hyphen, if any. 40 | str_transliterated=${str_transliterated%-} 41 | # Convert to lower case 42 | str_transliterated=${str_transliterated,,} 43 | 44 | printf "%s" "${str_transliterated}" 45 | } 46 | -------------------------------------------------------------------------------- /_join.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::join(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Joins multiple strings into a single string, separated by another string. 11 | # 12 | # This function will accept an unlimited number of arguments. 13 | # Example: bfl::join "," "foo" "bar" "baz" 14 | # 15 | # @param string $glue 16 | # The character or characters that will be used to glue the strings together. 17 | # @param list $pieces 18 | # The list of strings to be combined. 19 | # 20 | # @return string $joined_string 21 | # The joined string. 22 | # 23 | # @example 24 | # bfl::join "," "foo" "bar" "baz" 25 | #----------------------------------------------------------------------------- 26 | bfl::join() { 27 | bfl::verify_arg_count "$#" 2 999 || exit 1 28 | 29 | declare -r glue="$1" 30 | 31 | # Delete the first positional parameter. 32 | shift 33 | 34 | # Create the pieces array from the remaining positional parameters. 35 | declare -a pieces=("$@") 36 | declare joined_string 37 | 38 | while (( "${#pieces[@]}" )); do 39 | if [[ "${#pieces[@]}" -eq "1" ]]; then 40 | joined_string+=$(printf "%s\\n" "${pieces[0]}") || bfl::die 41 | else 42 | joined_string+=$(printf "%s%s" "${pieces[0]}" "${glue}") || bfl::die 43 | fi 44 | pieces=("${pieces[@]:1}") # Shift the first element off of the array. 45 | done 46 | 47 | printf "%s" "${joined_string}" 48 | } 49 | -------------------------------------------------------------------------------- /_find_nearest_integer.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::find_nearest_integer(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Finds the nearest integer to a target integer from a list of integers. 11 | # 12 | # @param string $target 13 | # The target integer. 14 | # @param string $list 15 | # A list of integers. 16 | # 17 | # @return string $nearest 18 | # Integer in list that is nearest to the target. 19 | # 20 | # @example 21 | # bfl::find_nearest_integer "4" "0 3 6 9 12" 22 | #------------------------------------------------------------------------------ 23 | bfl::find_nearest_integer() { 24 | bfl::verify_arg_count "$#" 2 2 || exit 1 25 | 26 | declare -r target="$1" 27 | declare -ar list="($2)" 28 | 29 | declare nearest 30 | 31 | declare -r regex="^(-{0,1}[0-9]+\s*)+$" 32 | declare abs_diff 33 | declare diff 34 | declare item 35 | declare table 36 | 37 | bfl::is_integer "${target}" \ 38 | || bfl::die "Expected integer, received ${target}." 39 | 40 | if ! [[ "${list[*]}" =~ ${regex} ]]; then 41 | bfl::die "Expected list of integers, received ${list[*]}." 42 | fi 43 | 44 | for item in "${list[@]}"; do 45 | diff=$((target-item)) || bfl::die 46 | abs_diff="${diff/-/}" 47 | table+="${item} ${abs_diff}\\n" 48 | done 49 | 50 | # Remove final line feed from $table. 51 | table=${table::-2} 52 | 53 | nearest=$(echo -e "${table}" | sort -n -k2 | head -n1 | cut -f1 -d " ") || bfl::die 54 | printf "%s" "${nearest}" 55 | } 56 | -------------------------------------------------------------------------------- /templates/_library_function.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::library_function(). # TODO 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Does something. # TODO 11 | # 12 | # Detailed description. Use multiple lines if needed. # TODO 13 | # 14 | # @param type $foo # TODO 15 | # Description. # TODO 16 | # @param type $bar # TODO 17 | # Description. # TODO 18 | # 19 | # @return type $baz # TODO 20 | # Description. # TODO 21 | # 22 | # @example 23 | # bfl::library_function "Fred" "George" # TODO 24 | #------------------------------------------------------------------------------ 25 | bfl::library_function() { 26 | # Verify argument count. 27 | bfl::verify_arg_count "$#" 2 2 || exit 1 # TODO 28 | 29 | # Verify dependencies. 30 | bfl::verify_dependencies "printf" # TODO 31 | 32 | # Declare positional arguments (readonly, sorted by position). 33 | declare -r foo="$1" # TODO 34 | declare -r bar="$2" # TODO 35 | 36 | # Declare return value. 37 | declare baz # TODO 38 | 39 | # Declare readonly variables (sorted by name). 40 | declare -r wibble="Harry" # TODO 41 | declare -r wobble="Ron" # TODO 42 | 43 | # Declare all other variables (sorted by name). 44 | declare eggs="Dean" # TODO 45 | declare ham="Seamus" # TODO 46 | 47 | # Verify argument values. 48 | bfl::is_empty "${foo}" && bfl::die "Foo is required." # TODO 49 | bfl::is_empty "${bar}" && bfl::die "Bar is required." # TODO 50 | 51 | # Build the return value. 52 | baz="${foo}, ${bar}, ${wibble}, ${wobble}, ${eggs}, and ${ham}." # TODO 53 | 54 | # Print the return value. 55 | printf "%s\\n" "${baz}" # TODO 56 | } 57 | -------------------------------------------------------------------------------- /_send_sms_msg.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::send_sms_msg(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Sends an SMS message via Amazon Simple Notification Service (SNS). 11 | # 12 | # @param string $phone_number 13 | # Recipient's phone number, including country code. 14 | # @param string $message 15 | # Example: "This is line one.\\nThis is line two.\\n" 16 | # 17 | # @example 18 | # bfl::send_sms_msg "+12065550100" "Line 1.\\nLine 2." 19 | #------------------------------------------------------------------------------ 20 | bfl::send_sms_msg() { 21 | bfl::verify_arg_count "$#" 2 2 || exit 1 22 | bfl::verify_dependencies "aws" 23 | 24 | declare -r phone_number="$1" 25 | declare -r message="$2" 26 | declare -r phone_number_regex="^\\+[0-9]{6,}$" 27 | declare error_msg 28 | 29 | if bfl::is_empty "${phone_number}"; then 30 | bfl::die "The recipient's phone number was not specified." 31 | fi 32 | 33 | if bfl::is_empty "${message}"; then 34 | bfl::die "The message was not specified." 35 | fi 36 | 37 | # Make sure phone number is properly formatted. 38 | if [[ ! "${phone_number}" =~ ${phone_number_regex} ]]; then 39 | error_msg="The recipient's phone number is improperly formatted.\\n" 40 | error_msg+="Expected a plus sign followed by six or more digits, " 41 | error_msg+="received ${phone_number}." 42 | bfl::die "${error_msg}" 43 | fi 44 | 45 | # Backslash escapes such as \n (newline) in the message string must be 46 | # interpreted before sending the message. 47 | interpreted_message=$(printf "%b" "${message}") || bfl::die 48 | 49 | # Send the message. 50 | aws sns publish --phone-number "${phone_number}" \ 51 | --message "${interpreted_message}" || bfl::die 52 | } 53 | -------------------------------------------------------------------------------- /_generate_password.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::generate_password(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Generates a random password. 11 | # 12 | # Password characteristics: 13 | # - At least one lowercase letter 14 | # - At least one uppercase letter 15 | # - At least one digit 16 | # - One underscore placed randomly in the middle. 17 | # - Minimum length of 8 18 | # 19 | # The underscore placed randomly in the middle ensures that the password will 20 | # have at least one special character. The underscore is probably the most 21 | # benign special character (i.e., it won't break quoted strings, doesn't 22 | # contain escape sequences, etc.). 23 | # 24 | # @param int $pswd_length 25 | # The length of the desired password. 26 | # 27 | # @return string $password 28 | # A random password 29 | # 30 | # @example 31 | # bfl::generate_password "16" 32 | #------------------------------------------------------------------------------ 33 | bfl::generate_password() { 34 | bfl::verify_arg_count "$#" 1 1 || exit 1 35 | bfl::verify_dependencies "pwgen" "shuf" 36 | 37 | declare -r pswd_length="$1" 38 | declare password 39 | declare -r min_pswd_length=8 40 | declare length_one 41 | declare length_two 42 | 43 | bfl::is_positive_integer "${pswd_length}" \ 44 | || bfl::die "Expected positive integer, received ${pswd_length}." 45 | 46 | if [[ "${pswd_length}" -lt "${min_pswd_length}" ]]; then 47 | bfl::die "Expected integer >= ${min_pswd_length}, received ${pswd_length}." 48 | fi 49 | 50 | length_one=$(shuf -i 1-$((pswd_length-2)) -n 1) || bfl::die 51 | length_two=$((pswd_length-length_one-1)) || bfl::die 52 | password=$(pwgen -cns "$length_one" 1)_$(pwgen -cns "$length_two" 1) || bfl::die 53 | 54 | printf "%s" "${password}" 55 | } 56 | -------------------------------------------------------------------------------- /_is_apache_vhost.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::is_apache_vhost(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Checks if the given path is the root of an Apache virtual host. 11 | # 12 | # @param string $path 13 | # A relative path, absolute path, or symbolic link. 14 | # @param string $sites_enabled [optional] 15 | # Absolute path to Apache's "sites-enabled" directory. 16 | # Defaults value is /etc/apache2/sites-enabled. 17 | # 18 | # @example 19 | # bfl::is_apache_vhost "./foo" 20 | # @example 21 | # bfl::is_apache_vhost "./foo" "/etc/apache2/sites-enabled" 22 | #------------------------------------------------------------------------------ 23 | bfl::is_apache_vhost() { 24 | # Verify argument count. 25 | bfl::verify_arg_count "$#" 1 2 || exit 1 26 | 27 | # Verify dependencies. 28 | bfl::verify_dependencies "grep" 29 | 30 | # Declare positional arguments (readonly, sorted by position). 31 | declare -r path="$1" 32 | declare -r sites_enabled="${2:-"/etc/apache2/sites-enabled"}" 33 | 34 | # Declare all other variables (sorted by name). 35 | declare canonical_path 36 | declare canonical_sites_enabled 37 | 38 | # Verify argument values. 39 | bfl::is_empty "${path}" && 40 | bfl::die "path is required." 41 | bfl::is_empty "${sites_enabled}" && 42 | bfl::die "path_sites_enabled is required." 43 | 44 | # Get canonical paths. 45 | canonical_path=$(bfl::get_directory_path "${path}") || 46 | bfl::die "Unable to determine canonical path to ${path}." 47 | canonical_sites_enabled=$(bfl::get_directory_path "${sites_enabled}") || 48 | bfl::die "Unable to determine canonical path to ${sites_enabled}." 49 | 50 | grep -q -P -R -m1 \ 51 | "DocumentRoot\\s+${canonical_path}$" \ 52 | "${canonical_sites_enabled}" 53 | } 54 | -------------------------------------------------------------------------------- /_send_mail_msg.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::send_mail_msg(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Sends an email message via sendmail. 11 | # 12 | # @param string $to 13 | # Message recipient or recipients. 14 | # Examples: 15 | # - foo@example.com 16 | # - foo@example.com, bar@example.com 17 | # - Foo 18 | # - Foo , Bar 19 | # @param string $from 20 | # Message sender. 21 | # Examples: 22 | # - foo@example. 23 | # - Foo 24 | # @param string $envelope_from 25 | # Envelope sender address. 26 | # Example: foo@example.com 27 | # @param string $subject 28 | # Message subject. 29 | # @param string $body 30 | # Message body. 31 | # Example: "This is line one.\\nThis is line two.\\n" 32 | # 33 | # @example 34 | # bfl::send_mail_msg "a@b.com" "x@y.com" "x@y.com" "Test" "Line 1.\\nLine 2." 35 | #------------------------------------------------------------------------------ 36 | bfl::send_mail_msg() { 37 | bfl::verify_arg_count "$#" 5 5 || exit 1 38 | bfl::verify_dependencies "sendmail" 39 | 40 | declare -r to="$1" 41 | declare -r from="$2" 42 | declare -r envelope_from="$3" 43 | declare -r subject="$4" 44 | declare -r body="$5" 45 | declare message 46 | 47 | bfl::is_empty "${to}" \ 48 | && bfl::die "The message recipient was not specified." 49 | bfl::is_empty "${from}" \ 50 | && bfl::die "The message sender was not specified." 51 | bfl::is_empty "${envelope_from}" \ 52 | && bfl::die "The envelope sender address was not specified." 53 | bfl::is_empty "${subject}" \ 54 | && bfl::die "The message subject was not specified." 55 | bfl::is_empty "${body}" \ 56 | && bfl::die "The message body was not specified." 57 | 58 | # Format the message. 59 | message=$(printf "To: %s\\nFrom: %s\\nSubject: %s\\n\\n%b" \ 60 | "${to}" \ 61 | "${from}" \ 62 | "${subject}" \ 63 | "${body}") || bfl::die 64 | 65 | # Send the message. 66 | echo "$message" | sendmail -f "$envelope_from" "$to" || bfl::die 67 | } 68 | -------------------------------------------------------------------------------- /_verify_arg_count.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::verify_arg_count(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Verifies the number of arguments received against expected values. 11 | # 12 | # Other functions in this library call this function to verify the number of 13 | # arguments received. To prevent infinite loops, this function must not call 14 | # any other function in this library, other than bfl::die. 15 | # 16 | # That is why we are essentially recreating: 17 | # - bfl::verify_arg_count() 18 | # - bfl::is_integer() 19 | # 20 | # @param int $actual_arg_count 21 | # Actual number of arguments received. 22 | # @param int $expected_arg_count_min 23 | # Minimum number of arguments expected. 24 | # @param int $expected_arg_count_max 25 | # Maximum number of arguments expected. 26 | # 27 | # @example 28 | # bfl::verify_arg_count "$#" 2 3 29 | # 30 | # shellcheck disable=SC2154 31 | #------------------------------------------------------------------------------ 32 | bfl::verify_arg_count() { 33 | # Verify argument count. 34 | if [[ "$#" -ne "3" ]]; then 35 | bfl::die "Invalid number of arguments. Expected 3, received $#." 36 | fi 37 | declare -r actual_arg_count="$1" 38 | declare -r expected_arg_count_min="$2" 39 | declare -r expected_arg_count_max="$3" 40 | declare -r regex="^[0-9]+$" 41 | declare error_msg 42 | 43 | # Make sure all of the arguments are integers. 44 | if ! [[ "${actual_arg_count}" =~ ${regex} ]] ; then 45 | bfl::die "\"${actual_arg_count}\" is not an integer." 46 | fi 47 | if ! [[ "${expected_arg_count_min}" =~ ${regex} ]] ; then 48 | bfl::die "\"${expected_arg_count_min}\" is not an integer." 49 | fi 50 | if ! [[ "${expected_arg_count_max}" =~ ${regex} ]] ; then 51 | bfl::die "\"${expected_arg_count_max}\" is not an integer." 52 | fi 53 | 54 | # Test. 55 | if [[ "${actual_arg_count}" -lt "${expected_arg_count_min}" || \ 56 | "${actual_arg_count}" -gt "${expected_arg_count_max}" ]]; then 57 | if [[ "${expected_arg_count_min}" -eq "${expected_arg_count_max}" ]]; then 58 | error_msg="Invalid number of arguments. Expected " 59 | error_msg+="${expected_arg_count_min}, received ${actual_arg_count}." 60 | else 61 | error_msg="Invalid number of arguments. Expected between " 62 | error_msg+="${expected_arg_count_min} and ${expected_arg_count_max}, " 63 | error_msg+="received ${actual_arg_count}." 64 | fi 65 | printf "%b\\n" "${bfl_aes_red}Error. ${error_msg}${bfl_aes_reset}" 1>&2 66 | return 1 67 | fi 68 | } 69 | -------------------------------------------------------------------------------- /templates/script: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Does something. # TODO 6 | # 7 | # Detailed description. Use multiple lines if needed. # TODO 8 | #------------------------------------------------------------------------------ 9 | 10 | #------------------------------------------------------------------------------ 11 | # @function 12 | # Displays usage message. 13 | # 14 | # @return string $msg 15 | # The usage message. 16 | #------------------------------------------------------------------------------ 17 | usage() { 18 | declare msg 19 | msg=$(cat <&2 60 | exit 1 61 | fi 62 | 63 | # Display usage message if requested. 64 | [[ "$#" -gt 0 && ("$1" = "-h" || "$1" = "--help") ]] && { usage; exit 0; } 65 | 66 | # Verify argument count. 67 | bfl::verify_arg_count "$#" 2 2 || { usage; exit 1; } # TODO 68 | 69 | # Verify dependencies. 70 | bfl::verify_dependencies "printf" # TODO 71 | 72 | # Declare positional arguments (readonly, sorted by position). 73 | declare -r foo="$1" # TODO 74 | declare -r bar="$2" # TODO 75 | 76 | # Declare readonly variables (sorted by name). 77 | declare -r wibble="Harry" # TODO 78 | declare -r wobble="Ron" # TODO 79 | 80 | # Declare all other variables (sorted by name). 81 | declare eggs="Dean" # TODO 82 | declare ham="Seamus" # TODO 83 | 84 | # Verify argument values. 85 | bfl::is_empty "${foo}" && bfl::die "Foo is required." # TODO 86 | bfl::is_empty "${bar}" && bfl::die "Bar is required." # TODO 87 | 88 | # TODO 89 | printf "%s\\n" "${foo}, ${bar}, ${wibble}, ${wobble}, ${eggs}, and ${ham}." 90 | } 91 | 92 | set -euo pipefail 93 | trap cleanup EXIT 94 | main "$@" 95 | -------------------------------------------------------------------------------- /autoload.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Sources files adjacent to (in the same directory as) this script. 6 | # 7 | # This is the required directory structure: 8 | # 9 | # └── library (directory name and location are irrelevant) 10 | # ├── autoload.sh 11 | # ├── _file_1.sh 12 | # ├── _file_2.sh 13 | # └── _file_3.sh 14 | # 15 | # This script defines and then calls the autoload function. 16 | # 17 | # The autoload function loops through the files in the library directory, and 18 | # sources file names that begin with an underscore. 19 | # 20 | # An "underscore" file should contain one and only one function. The file name 21 | # should be equal to the function name, preceded by an underscore. 22 | # 23 | # So here's the scenario... 24 | # 25 | # You are creating a script ($HOME/foo.sh) to parse a text file. You need to 26 | # trim (remove leading and trailing spaces) some strings. Trimming is a common 27 | # task, a capability you are likely to need within other scripts. 28 | # 29 | # Instead of writing a trim function within foo.sh, write the function within 30 | # a new file named _trim.sh in the library directory. 31 | # 32 | # Finally, source path/to/autoload.sh at the beginning of foo.sh. All of the 33 | # functions in the library are now available to foo.sh. 34 | # 35 | # The relative path from foo.sh to autoload.sh is irrelevant. 36 | # 37 | # There is no need to set the executable bit on any of the files in the 38 | # library directory. In fact, Google's "Shell Style Guide" specifically forbids 39 | # this: 40 | # 41 | # "Libraries must have a .sh extension and should not be executable." 42 | # 43 | # See https://google.github.io/styleguide/shell.xml#File_Extensions. 44 | # 45 | # Logical functions in this library, such as bfl::is_integer() or 46 | # bfl::is_empty(), should not output any messages. They should only return 0 47 | # if true or return 1 if false. 48 | # 49 | # To simplify usage, place this line at the top of $HOME/.bashrc: 50 | # 51 | # export BASH_FUNCTION_LIBRARY="$HOME/path/to/autoloader.sh" 52 | # 53 | # Then, at the top of each new script add: 54 | # 55 | # if ! source "${BASH_FUNCTION_LIBRARY}"; then 56 | # printf "Error. Unable to source BASH_FUNCTION_LIBRARY.\\n" 1>&2 57 | # exit 1 58 | # fi 59 | # 60 | # shellcheck disable=SC1090 61 | #------------------------------------------------------------------------------ 62 | 63 | #------------------------------------------------------------------------------ 64 | # @function 65 | # Sources files adjacent to (in the same directory as) this script. 66 | # 67 | # This will only source file names that begin with an underscore. 68 | #------------------------------------------------------------------------------ 69 | bfl::autoload() { 70 | declare autoload_canonical_path # Canonical path to this file. 71 | declare autoload_directory # Directory in which this file resides. 72 | declare file 73 | 74 | autoload_canonical_path=$(readlink -e "${BASH_SOURCE[0]}") || exit 1 75 | autoload_directory=$(dirname "${autoload_canonical_path}") || exit 1 76 | 77 | for file in "${autoload_directory}"/_*; do 78 | source "${file}" || exit 1 79 | done 80 | } 81 | 82 | bfl::autoload 83 | -------------------------------------------------------------------------------- /examples/session-info: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Displays a banner with user and system information. 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Displays usage message. 11 | # 12 | # @return string $msg 13 | # The usage message. 14 | #------------------------------------------------------------------------------ 15 | usage() { 16 | declare msg 17 | msg=$(cat <&2 54 | exit 1 55 | fi 56 | 57 | # Display usage message if requested. 58 | [[ "$#" -gt 0 && ("$1" = "-h" || "$1" = "--help") ]] && { usage; exit 0; } 59 | 60 | # Verify argument count. 61 | bfl::verify_arg_count "$#" 0 1 || { usage; exit 1; } 62 | 63 | # Verify dependencies. 64 | bfl::verify_dependencies "curl" 65 | 66 | # Declare positional arguments (readonly, sorted by position). 67 | declare -r color="${1:-"white"}" 68 | 69 | # Declare all other variables (sorted by name). 70 | declare border 71 | declare date_now 72 | declare host 73 | declare ip_address_private 74 | declare ip_address_public 75 | declare name_of_color_constant 76 | declare time_now 77 | declare user 78 | declare width 79 | 80 | # Verify argument values. 81 | case "${color}" in 82 | "blue"|"cyan"|"green"|"magenta"|"red"|"yellow"|"white" ) 83 | name_of_color_constant="bfl_aes_${color}" 84 | ;; 85 | * ) 86 | bfl::error "The specified color is not supported." && { usage; exit 1; } 87 | ;; 88 | esac 89 | 90 | # Get values to display. 91 | date_now=$(date "+%A, %B %-d, %Y") || 92 | bfl::die "Unable to determine date." 93 | host=$(hostname) || 94 | bfl::die "Unable to determine hostname ." 95 | ip_address_private=$(ip route get 1 | head -n1 | cut -d' ' -f7) || 96 | bfl::die "Unable to determine private IP address." 97 | ip_address_public=$(curl -s --max-time 5 https://ipinfo.io/ip) || 98 | bfl::die "Unable to determine public IP address." 99 | time_now=$(date "+%-l:%M %p %Z") || 100 | bfl::die "Unable to determine time." 101 | user=$(whoami) || 102 | bfl::die "Unable to determine user." 103 | 104 | # Create border. 105 | width=$((21+${#date_now})) 106 | border=$(bfl::repeat "=" "${width}") || 107 | bfl::die "Unable to create a repeated string." 108 | 109 | # Display the banner. 110 | printf "%b\\n" "${!name_of_color_constant}" # Indirect variable expansion. 111 | printf "%s\\n" "${border}" 112 | column -t -s "|$" <<<" 113 | User:|${user} 114 | Hostname:|${host} 115 | Private IP address:|${ip_address_private} 116 | Public IP address:|${ip_address_public} 117 | Date:|${date_now} 118 | Time:|${time_now} 119 | " 120 | printf "%s\\n" "${border}" 121 | printf "\\n" 122 | } 123 | 124 | set -euo pipefail 125 | trap cleanup EXIT 126 | main "$@" 127 | -------------------------------------------------------------------------------- /docs/error-handling.md: -------------------------------------------------------------------------------- 1 | # Bash Function Library 2 | 3 | ## Error Handling 4 | 5 | [Framework](#framework) 6 | [Guidelines](#guidelines) 7 | [Exit with Command Substitution](#exit-with-command-substitution) 8 | 9 | ### Framework 10 | 11 | The `bfl::die` function calls `exit 1`. If the chain of commands leading to 12 | `bfl::die` is direct (no command substitution), the parent script exits when 13 | `bfl::die` fires. If command substitution occurs **anywhere** in the chain of 14 | commands leading to `bfl::die`, the parent script will **not** exit because 15 | command substitution spawns a subshell. 16 | See [Exit with Command Substitution](#exit-with-command-substitution) 17 | for a detailed explanation. 18 | 19 | Upon error, all library functions except `bfl::verify_arg_count` call 20 | `bfl::die` with an error message. For example: 21 | 22 | ```bash 23 | bfl::foo () { 24 | if [[ ! -f "${file}" ]]; then 25 | bfl::die "${file} does not exist." 26 | fi 27 | } 28 | ``` 29 | 30 | The `bfl::verify_arg_count` function **does not** call `bfl::die` on error. 31 | Instead, `bfl::verify_arg_count` calls `return 1` upon error. 32 | This exception allows the parent script to call a usage function when the 33 | argument count is incorrect. For example: 34 | 35 | ```bash 36 | bfl::verify_arg_count "$#" 1 3 || { usage; exit 1; } 37 | ``` 38 | 39 | ### Guidelines 40 | 41 | 1\) Within the `main()` function of a script, if `bfl::verify_arg_count` fails, 42 | display the usage message. For example: 43 | 44 | ```bash 45 | bfl::verify_arg_count "$#" 1 3 || { usage; exit 1; } 46 | ``` 47 | 48 | 2\) Within any other function, if `bfl::verify_arg_count` fails, exit 1. For 49 | example: 50 | 51 | ```bash 52 | bfl::verify_arg_count "$#" 1 3 || exit 1 53 | ``` 54 | 55 | Although you could call `bfl::die "foo"` instead of `exit 1`, it would have the 56 | same result but with a second error message. Either way is fine, but prefer the 57 | former. 58 | 59 | 3\) Except for `bfl::verify_arg_count` there is no need to test the exit status 60 | when calling a library function directly—library functions call bfl::die 61 | upon error. For example: 62 | 63 | ```bash 64 | bfl::foo "bar" 65 | ``` 66 | 67 | 3\) Always test the exit status when performing command substitution. For 68 | example: 69 | 70 | ```bash 71 | var=$(bfl::foo "bar") || bfl::die "Unable to foo the bar." 72 | var=$(pwd) || bfl::die "Unable to determine working directory." 73 | ``` 74 | 75 | 4\) Logical library functions such as `bfl::is_empty` and `bfl::is_integer` 76 | have an exit status of 0 if true, 1 if false. By definition you will always 77 | test the exit status, either explicitly or implicitly, when using logical 78 | library functions. For example: 79 | 80 | ```bash 81 | if bfl::is_integer "${foo}"; then 82 | printf "%s is an integer.\\n" "${foo}" 83 | else 84 | printf "%s is not an integer.\\n" "${foo}" 85 | fi 86 | 87 | bfl::is_empty "${bar}" && printf "\${bar} is empty.\\n" "${bar}" 88 | ``` 89 | 90 | ### Exit with Command Substitution 91 | 92 | Define a function within a script: 93 | 94 | ```bash 95 | my_function() { 96 | exit 1 97 | } 98 | ``` 99 | 100 | Now call the function directly: 101 | 102 | ```bash 103 | my_function 104 | ``` 105 | 106 | The script will exit. 107 | 108 | Now, instead of calling the function directly, use command substitution: 109 | 110 | ```bash 111 | var=$(my_function) 112 | ``` 113 | 114 | In this case the script will *not* exit because command substitution occurs in 115 | a subshell. The subshell exits, not the shell or script that invoked it. There 116 | are two ways to address this: 117 | 118 | 1\) Test the exit status of command substitution. For example: 119 | 120 | ```bash 121 | var=$(bfl::trim "${foo}") || exit 1 122 | ``` 123 | 124 | 2\) Configure the shell or script to exit if any command exits with a non-zero 125 | status with `set -e`. In this configuration, the shell or script that invokes 126 | command substitution will exit when the subshell exits. 127 | 128 | Recommendation: code defensively by testing the exit status of all but the most 129 | trivial commands, and invoke `set -euo pipefail` at the beginning of the 130 | script. While we don't want to rely on `set -e`, it may catch items we miss. 131 | 132 | Do both—take no chances! 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bash Function Library 2 | 3 | ## Table of Contents 4 | 5 | * [Overview](#overview) 6 | * [Installation](#installation) 7 | * [Configuration](#configuration) 8 | * [Examples](#examples) 9 | * [Templates](#templates) 10 | * [Documentation](#documentation) 11 | 12 | ## Overview 13 | 14 | The Bash Function Library is a collection of utility functions. The library is 15 | not, and was never intended to be, POSIX compliant. Each function is 16 | namespaced with the `bfl::` prefix. For example, to trim a string: 17 | 18 | ```bash 19 | bfl::trim "${var}" 20 | ``` 21 | 22 | The calling script must source the entire library; some of the functions depend 23 | on one or more of the others. Source the entire library by sourcing 24 | autoload.sh. See the comments in autoload.sh for an explanation of the loading 25 | process. 26 | 27 | ## Installation 28 | 29 | 1\. Clone this repository into `${HOME}/.lib/bfl`. 30 | 31 | ```bash 32 | git clone https://github.com/jmooring/bash-function-library.git "${HOME}/.lib/bfl" 33 | ``` 34 | 35 | 2\. Create a permanent environment variable containing the path to the 36 | autoloader. 37 | 38 | ```bash 39 | heredoc=$(cat<> "${HOME}/.bashrc" 48 | ``` 49 | 50 | 3\. Verify that the BASH_FUNCTION_LIBRARY environment variable is correct. 51 | 52 | ```bash 53 | source "${HOME}/.bashrc" 54 | printf "%s\\n" "${BASH_FUNCTION_LIBRARY}" 55 | ``` 56 | 57 | 4\. Test using the `bfl::repeat` library function. 58 | 59 | ```bash 60 | if source "${BASH_FUNCTION_LIBRARY}"; then 61 | printf "%s\\n" "$(bfl::repeat "=" "40")" 62 | else 63 | printf "Error. Unable to source BASH_FUNCTION_LIBRARY.\\n" 1>&2 64 | fi 65 | ``` 66 | 67 | ## Configuration 68 | 69 | ### Color Output 70 | 71 | Library functions such as `bfl::die` and `bfl::warn` produce color output via 72 | ANSI escape sequences. For example, `bfl::die` prints error messages in red, 73 | while `bfl::warn` prints warning messages in yellow. 74 | 75 | Instead of hardcoding ANSI escape sequences to produce color output, the 76 | `bfl::declare_ansi_escape_sequences` library function defines global variables 77 | for common color and formatting cases. This function is called when the Bash 78 | Function Library is initially sourced. 79 | 80 | The documentation contains a [complete 81 | list](docs/function-list.md#bfl_declare_ansi_escape_sequences) of the defined 82 | ANSI escape sequence variables. 83 | 84 | Each of the following examples prints the word "foo" in yellow: 85 | 86 | ```bash 87 | echo -e "${bfl_aes_yellow}foo${bfl_aes_reset}" 88 | printf "${bfl_aes_yellow}%s${bfl_aes_reset}\\n" "foo" 89 | printf "%b\\n" "${bfl_aes_yellow}foo${bfl_aes_reset}" 90 | ``` 91 | 92 | In some cases it may be desirable to disable color output. For example, let's 93 | say you've written a script leveraging this library. When you run the script in 94 | a terminal, you'd like to see the error messages in color. However, when run as 95 | a cron job, you don't want to see the ANSI escape sequences surrounding error 96 | messages when viewing logs or emails sent by cron. 97 | 98 | To disable color output, set the BASH_FUNCTION_LIBRARY_COLOR_OUTPUT environment 99 | variable to "disabled" before sourcing the autoloader. For example: 100 | 101 | ```bash 102 | export BASH_FUNCTION_LIBRARY_COLOR_OUTPUT=disabled 103 | if ! source "${BASH_FUNCTION_LIBRARY}"; then 104 | printf "Error. Unable to source BASH_FUNCTION_LIBRARY.\\n" 1>&2 105 | exit 1 106 | fi 107 | ``` 108 | 109 | ## Examples 110 | 111 | [examples/\_introduce.sh](examples/_introduce.sh) 112 | 113 | > This library function is simple and heavily documented—a tutorial. 114 | 115 | [examples/session-info](examples/session-info) 116 | 117 | > This script leverages the Bash Function Library, displaying a banner with 118 | user and system information. 119 | 120 | ## Templates 121 | 122 | [templates/_library_function.sh](templates/_library_function.sh) 123 | 124 | > Use this template to create a new library function. 125 | 126 | [templates/script](templates/script) 127 | 128 | > Use this template to create a script which leverages the Bash Function 129 | Library. 130 | 131 | ## Documentation 132 | 133 | [docs/function-list.md](docs/function-list.md) 134 | 135 | > Summary of library functions. 136 | 137 | [docs/error-handling.md](docs/error-handling.md) 138 | 139 | > Notes on error handling. 140 | 141 | [docs/coding-standards.md](docs/coding-standards.md) 142 | 143 | > Coding standards. 144 | -------------------------------------------------------------------------------- /docs/makedoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Creates documentation for library functions. 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Displays usage message. 11 | # 12 | # @return string $msg 13 | # The usage message. 14 | #------------------------------------------------------------------------------ 15 | usage() { 16 | declare msg 17 | msg=$(cat <&2 38 | exit 1 39 | fi 40 | 41 | # Verify argument count. 42 | bfl::verify_arg_count "$#" 0 0 || { usage; exit 1; } 43 | 44 | # Verify dependencies. 45 | bfl::verify_dependencies "grep" "sed" 46 | 47 | # Declare readonly variables (sorted by name). 48 | declare -r btx3="\\x60\\x60\\x60" # 3 backticks 49 | declare -r header="# Bash Function Library\\n\\n## Function List" 50 | declare -r output_file_name="function-list.md" 51 | 52 | # Declare all other variables (sorted by name). 53 | declare body 54 | declare file 55 | declare footer 56 | declare func_examples 57 | declare func_name 58 | declare func_params 59 | declare func_returns 60 | declare func_summary 61 | declare header_examples 62 | declare header_params 63 | declare header_returns 64 | 65 | declare toc 66 | 67 | # Create footer. 68 | footer="*Last updated: $(date --iso-8601=s).*" 69 | 70 | # Loop through the files. 71 | for file in "$(dirname "${BASH_FUNCTION_LIBRARY}")"/_*; do 72 | 73 | # Set the headers for each section. Need to do this each time through the 74 | # loop because one or more may be pluralized if there is more than one. 75 | header_examples="Example" 76 | header_params="Parameter" 77 | header_returns="Return" 78 | 79 | # Find the function name (one line). 80 | func_name=$(grep -Eo -m1 "bfl::.+" "${file}" | sed 's/().*//') \ 81 | || bfl::die "Unable to find function name" 82 | 83 | # Find the function description (one entry). 84 | func_summary=$(grep -A1 "@function" "${file}" | \ 85 | tail -n1 | \ 86 | sed 's/^# *//') \ 87 | || bfl::die "Unable to find function description." 88 | 89 | # The sed command to format @param and @return entries: 90 | # 91 | # 1. Remove leading "#" and spaces from each line. 92 | # 2. Add ">" to the beginning of each line. 93 | # 3. Replace ">@tag " with a newline. 94 | 95 | # Find the function parameters (zero or more entries). 96 | set +e 97 | func_params=$(grep -A1 --no-group-separator "# *@param" "${file}" | \ 98 | sed 's/^# *// ; s/^/>/ ; s/>@param /\\n/') 99 | [[ "$(grep -c "# *@param" "${file}")" -gt "1" ]] && header_params+="s" 100 | set -e 101 | 102 | # Find the function returns (zero or more entries). 103 | set +e 104 | func_returns=$(grep -A1 --no-group-separator "# *@return" "${file}" | \ 105 | sed 's/^# *// ; s/^/>/ ; s/>@return /\\n/') 106 | [[ "$(grep -c "# *@return" "${file}")" -gt "1" ]] && header_returns+="s" 107 | set -e 108 | 109 | # The sed command to format @example entries: 110 | # 111 | # 1. Delete the line containing the @example tag. 112 | # 2. Remove leading "#" and spaces from each line. 113 | 114 | # Find the function examples (zero or more entries). 115 | set +e 116 | func_examples=$(grep -A1 --no-group-separator "# *@example" "${file}" | \ 117 | sed '/.*@example.*/d ; s/^# *//' ) 118 | [[ "$(grep -c "# *@example" "${file}")" -gt "1" ]] && header_examples+="s" 119 | set -e 120 | 121 | # Surround the examples with 3 backticks. 122 | func_examples="\\n${btx3}bash\\n${func_examples}\\n${btx3}\\n" 123 | 124 | # Add to the table of contents. 125 | toc+="* [${func_name}](#${func_name//::/})\\n" 126 | 127 | # Add to the body. 128 | body+="## ${func_name}\\n\\n" 129 | body+="${func_summary}\\n\\n" 130 | ! bfl::is_empty "${func_params}" && body+="**${header_params}**\\n" 131 | ! bfl::is_empty "${func_params}" && body+="${func_params}\\n\\n" 132 | ! bfl::is_empty "${func_returns}" && body+="**${header_returns}**\\n" 133 | ! bfl::is_empty "${func_returns}" && body+="${func_returns}\\n\\n" 134 | ! bfl::is_empty "${func_examples}" && body+="**${header_examples}**\\n" 135 | ! bfl::is_empty "${func_examples}" && body+="${func_examples}\\n" 136 | done 137 | 138 | printf "%b\\n\\n%b\\n%b---\\n%b\\n" \ 139 | "${header}" \ 140 | "${toc}" \ 141 | "${body}" \ 142 | "${footer}" \ 143 | > "$(dirname "${BASH_FUNCTION_LIBRARY}")/docs/${output_file_name}" 144 | } 145 | 146 | set -euo pipefail 147 | main "$@" 148 | -------------------------------------------------------------------------------- /_lorem.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Defines function: bfl::lorem(). 6 | #------------------------------------------------------------------------------ 7 | 8 | #------------------------------------------------------------------------------ 9 | # @function 10 | # Randomly extracts one or more sequential paragraphs from a given resource. 11 | # 12 | # The resources are located in the resources/lorem directory. Each resource 13 | # contains one paragraph per line. The resources were created from books 14 | # downloaded from Project Gutenberg (https://www.gutenberg.org), and then 15 | # edited to remove: 16 | # 17 | # 1) Front matter 18 | # 2) Back matter 19 | # 3) Footnotes 20 | # 4) Cross references 21 | # 5) Captions 22 | # 6) Any paragraph less than or equal to 200 characters. 23 | # 24 | # @param int $paragraphs (optional) 25 | # The number of paragraphs to extract (default: 1). 26 | # @param string $resource (optional) 27 | # The resource from which to extract the paragraphs (default: muir). 28 | # Valid resources: 29 | # - burroughs (The Breath of Life by John Burroughs) 30 | # - darwin (The Origin of Species by Charles Darwin) 31 | # - hugo (Les Miserables by Victor Hugo) 32 | # - mills (The Rocky Mountain Wonderland by Enos Mills) 33 | # - muir (Our National Parks by John Muir) 34 | # - virgil (The Aeneid by Virgil) 35 | # 36 | # @return string $text 37 | # The extracted paragraphs. 38 | # 39 | # @example 40 | # bfl::lorem 41 | # @example 42 | # bfl::lorem 2 43 | # @example 44 | # bfl::lorem 3 burroughs 45 | # @example 46 | # bfl::lorem 3 darwin 47 | # @example 48 | # bfl::lorem 3 mills 49 | # @example 50 | # bfl::lorem 3 muir 51 | # @example 52 | # bfl::lorem 3 virgil 53 | #------------------------------------------------------------------------------ 54 | bfl::lorem() { 55 | # Verify argument count. 56 | bfl::verify_arg_count "$#" 0 2 || exit 1 57 | 58 | # Verify dependencies. 59 | bfl::verify_dependencies "shuf" 60 | 61 | # Declare positional arguments (readonly, sorted by position). 62 | declare -r paragraphs="${1:-1}" 63 | declare -r resource="${2:-muir}" 64 | 65 | # Verify argument values. 66 | bfl::is_positive_integer "${paragraphs}" || 67 | bfl::die "The paragraph count must be a positive integer." 68 | 69 | # Declare return value. 70 | declare text 71 | 72 | # Declare all other variables (sorted by name). 73 | declare first_paragraph_number 74 | declare last_paragraph_number 75 | declare maximum_first_paragraph_number 76 | declare msg 77 | declare resource_directory 78 | declare resource_file 79 | declare resource_paragraph_count 80 | 81 | # Set the resource directory path. 82 | resource_directory=$(dirname "${BASH_FUNCTION_LIBRARY}")/resources/lorem || 83 | bfl::die "Unable to determine resource directory." 84 | 85 | # Select the resource file from which to extract paragraphs. 86 | case "${resource}" in 87 | "burroughs" ) 88 | resource_file=${resource_directory}/the-breath-of-life-by-john-burroughs.txt 89 | ;; 90 | "darwin" ) 91 | resource_file=${resource_directory}/the-origin-of-species-by-charles-darwin.txt 92 | ;; 93 | "hugo" ) 94 | resource_file=${resource_directory}/les-miserables-by-victor-hugo.txt 95 | ;; 96 | "mills" ) 97 | resource_file=${resource_directory}/the-rocky-mountain-wonderland-by-enos-mills.txt 98 | ;; 99 | "muir" ) 100 | resource_file=${resource_directory}/our-national-parks-by-john-muir.txt 101 | ;; 102 | "virgil" ) 103 | resource_file=${resource_directory}/the-aeneid-by-virgil.txt 104 | ;; 105 | * ) 106 | bfl::die "Unknown resource." 107 | ;; 108 | esac 109 | 110 | # Determine number of paragraphs in the resource file (assumes one per line). 111 | resource_paragraph_count=$(wc -l < "${resource_file}") || 112 | bfl::die "Unable to determine number of paragraphs in source file." 113 | 114 | # Make sure number of requested paragraphs does not exceed maximum. 115 | if [[ "${paragraphs}" -gt "${resource_paragraph_count}" ]]; then 116 | msg=$(cat <&2 32 | # exit 1 33 | # fi 34 | # 35 | # @return global string $bfl_aes_black 36 | # ANSI escape sequence for black. 37 | # @return global string $bfl_aes_black_bold 38 | # ANSI escape sequence for black + bold. 39 | # @return global string $bfl_aes_black_faint 40 | # ANSI escape sequence for black + faint. 41 | # @return global string $bfl_aes_black_underline 42 | # ANSI escape sequence for black + underline. 43 | # @return global string $bfl_aes_black_blink 44 | # ANSI escape sequence for black + blink. 45 | # @return global string $bfl_aes_black_reverse 46 | # ANSI escape sequence for black + reverse. 47 | # @return global string $bfl_aes_red 48 | # ANSI escape sequence for red. 49 | # @return global string $bfl_aes_red_bold 50 | # ANSI escape sequence for red + bold. 51 | # @return global string $bfl_aes_red_faint 52 | # ANSI escape sequence for red + faint. 53 | # @return global string $bfl_aes_red_underline 54 | # ANSI escape sequence for red + underline. 55 | # @return global string $bfl_aes_red_blink 56 | # ANSI escape sequence for red + blink. 57 | # @return global string $bfl_aes_red_reverse 58 | # ANSI escape sequence for red + reverse. 59 | # @return global string $bfl_aes_green 60 | # ANSI escape sequence for green. 61 | # @return global string $bfl_aes_green_bold 62 | # ANSI escape sequence for green + bold. 63 | # @return global string $bfl_aes_green_faint 64 | # ANSI escape sequence for green + faint. 65 | # @return global string $bfl_aes_green_underline 66 | # ANSI escape sequence for green + underline. 67 | # @return global string $bfl_aes_green_blink 68 | # ANSI escape sequence for green + blink. 69 | # @return global string $bfl_aes_green_reverse 70 | # ANSI escape sequence for green + reverse. 71 | # @return global string $bfl_aes_yellow 72 | # ANSI escape sequence for yellow. 73 | # @return global string $bfl_aes_yellow_bold 74 | # ANSI escape sequence for yellow + bold. 75 | # @return global string $bfl_aes_yellow_faint 76 | # ANSI escape sequence for yellow + faint. 77 | # @return global string $bfl_aes_yellow_underline 78 | # ANSI escape sequence for yellow + underline. 79 | # @return global string $bfl_aes_yellow_blink 80 | # ANSI escape sequence for yellow + blink. 81 | # @return global string $bfl_aes_yellow_reverse 82 | # ANSI escape sequence for yellow + reverse. 83 | # @return global string $bfl_aes_blue 84 | # ANSI escape sequence for blue. 85 | # @return global string $bfl_aes_blue_bold 86 | # ANSI escape sequence for blue + bold. 87 | # @return global string $bfl_aes_blue_faint 88 | # ANSI escape sequence for blue + faint. 89 | # @return global string $bfl_aes_blue_underline 90 | # ANSI escape sequence for blue + underline. 91 | # @return global string $bfl_aes_blue_blink 92 | # ANSI escape sequence for blue + blink. 93 | # @return global string $bfl_aes_blue_reverse 94 | # ANSI escape sequence for blue + reverse. 95 | # @return global string $bfl_aes_magenta 96 | # ANSI escape sequence for magenta. 97 | # @return global string $bfl_aes_magenta_bold 98 | # ANSI escape sequence for magenta + bold. 99 | # @return global string $bfl_aes_magenta_faint 100 | # ANSI escape sequence for magenta + faint. 101 | # @return global string $bfl_aes_magenta_underline 102 | # ANSI escape sequence for magenta + underline. 103 | # @return global string $bfl_aes_magenta_blink 104 | # ANSI escape sequence for magenta + blink. 105 | # @return global string $bfl_aes_magenta_reverse 106 | # ANSI escape sequence for magenta + reverse. 107 | # @return global string $bfl_aes_cyan 108 | # ANSI escape sequence for cyan. 109 | # @return global string $bfl_aes_cyan_bold 110 | # ANSI escape sequence for cyan + bold. 111 | # @return global string $bfl_aes_cyan_faint 112 | # ANSI escape sequence for cyan + faint. 113 | # @return global string $bfl_aes_cyan_underline 114 | # ANSI escape sequence for cyan + underline. 115 | # @return global string $bfl_aes_cyan_blink 116 | # ANSI escape sequence for cyan + blink. 117 | # @return global string $bfl_aes_cyan_reverse 118 | # ANSI escape sequence for cyan + reverse. 119 | # @return global string $bfl_aes_white 120 | # ANSI escape sequence for white. 121 | # @return global string $bfl_aes_white_bold 122 | # ANSI escape sequence for white + bold. 123 | # @return global string $bfl_aes_white_faint 124 | # ANSI escape sequence for white + faint. 125 | # @return global string $bfl_aes_white_underline 126 | # ANSI escape sequence for white + underline. 127 | # @return global string $bfl_aes_white_blink 128 | # ANSI escape sequence for white + blink. 129 | # @return global string $bfl_aes_white_reverse 130 | # ANSI escape sequence for white + reverse. 131 | # 132 | # @example: 133 | # bfl::declare_ansi_escape_sequences 134 | # 135 | # shellcheck disable=SC2034 136 | #------------------------------------------------------------------------------ 137 | bfl::declare_ansi_escape_sequences() { 138 | if [[ "${BASH_FUNCTION_LIBRARY_COLOR_OUTPUT:=enabled}" = "disabled" ]]; then 139 | 140 | declare -gr bfl_aes_black="" 141 | declare -gr bfl_aes_black_bold="" 142 | declare -gr bfl_aes_black_faint="" 143 | declare -gr bfl_aes_black_underline="" 144 | declare -gr bfl_aes_black_blink="" 145 | declare -gr bfl_aes_black_reverse="" 146 | 147 | declare -gr bfl_aes_red="" 148 | declare -gr bfl_aes_red_bold="" 149 | declare -gr bfl_aes_red_faint="" 150 | declare -gr bfl_aes_red_underline="" 151 | declare -gr bfl_aes_red_blink="" 152 | declare -gr bfl_aes_red_reverse="" 153 | 154 | declare -gr bfl_aes_green="" 155 | declare -gr bfl_aes_green_bold="" 156 | declare -gr bfl_aes_green_faint="" 157 | declare -gr bfl_aes_green_underline="" 158 | declare -gr bfl_aes_green_blink="" 159 | declare -gr bfl_aes_green_reverse="" 160 | 161 | declare -gr bfl_aes_yellow="" 162 | declare -gr bfl_aes_yellow_bold="" 163 | declare -gr bfl_aes_yellow_faint="" 164 | declare -gr bfl_aes_yellow_underline="" 165 | declare -gr bfl_aes_yellow_blink="" 166 | declare -gr bfl_aes_yellow_reverse="" 167 | 168 | declare -gr bfl_aes_blue="" 169 | declare -gr bfl_aes_blue_bold="" 170 | declare -gr bfl_aes_blue_faint="" 171 | declare -gr bfl_aes_blue_underline="" 172 | declare -gr bfl_aes_blue_blink="" 173 | declare -gr bfl_aes_blue_reverse="" 174 | 175 | declare -gr bfl_aes_magenta="" 176 | declare -gr bfl_aes_magenta_bold="" 177 | declare -gr bfl_aes_magenta_faint="" 178 | declare -gr bfl_aes_magenta_underline="" 179 | declare -gr bfl_aes_magenta_blink="" 180 | declare -gr bfl_aes_magenta_reverse="" 181 | 182 | declare -gr bfl_aes_cyan="" 183 | declare -gr bfl_aes_cyan_bold="" 184 | declare -gr bfl_aes_cyan_faint="" 185 | declare -gr bfl_aes_cyan_underline="" 186 | declare -gr bfl_aes_cyan_blink="" 187 | declare -gr bfl_aes_cyan_reverse="" 188 | 189 | declare -gr bfl_aes_white="" 190 | declare -gr bfl_aes_white_bold="" 191 | declare -gr bfl_aes_white_faint="" 192 | declare -gr bfl_aes_white_underline="" 193 | declare -gr bfl_aes_white_blink="" 194 | declare -gr bfl_aes_white_reverse="" 195 | 196 | declare -gr bfl_aes_reset="" 197 | 198 | else 199 | 200 | declare -gr bfl_aes_black="\\033[0;30m" 201 | declare -gr bfl_aes_black_bold="\\033[1;30m" 202 | declare -gr bfl_aes_black_faint="\\033[2;30m" 203 | declare -gr bfl_aes_black_underline="\\033[4;30m" 204 | declare -gr bfl_aes_black_blink="\\033[5;30m" 205 | declare -gr bfl_aes_black_reverse="\\033[7;30m" 206 | 207 | declare -gr bfl_aes_red="\\033[0;31m" 208 | declare -gr bfl_aes_red_bold="\\033[1;31m" 209 | declare -gr bfl_aes_red_faint="\\033[2;31m" 210 | declare -gr bfl_aes_red_underline="\\033[4;31m" 211 | declare -gr bfl_aes_red_blink="\\033[5;31m" 212 | declare -gr bfl_aes_red_reverse="\\033[7;31m" 213 | 214 | declare -gr bfl_aes_green="\\033[0;32m" 215 | declare -gr bfl_aes_green_bold="\\033[1;32m" 216 | declare -gr bfl_aes_green_faint="\\033[2;32m" 217 | declare -gr bfl_aes_green_underline="\\033[4;32m" 218 | declare -gr bfl_aes_green_blink="\\033[5;32m" 219 | declare -gr bfl_aes_green_reverse="\\033[7;32m" 220 | 221 | declare -gr bfl_aes_yellow="\\033[0;33m" 222 | declare -gr bfl_aes_yellow_bold="\\033[1;33m" 223 | declare -gr bfl_aes_yellow_faint="\\033[2;33m" 224 | declare -gr bfl_aes_yellow_underline="\\033[4;33m" 225 | declare -gr bfl_aes_yellow_blink="\\033[5;33m" 226 | declare -gr bfl_aes_yellow_reverse="\\033[7;33m" 227 | 228 | declare -gr bfl_aes_blue="\\033[0;34m" 229 | declare -gr bfl_aes_blue_bold="\\033[1;34m" 230 | declare -gr bfl_aes_blue_faint="\\033[2;34m" 231 | declare -gr bfl_aes_blue_underline="\\033[4;34m" 232 | declare -gr bfl_aes_blue_blink="\\033[5;34m" 233 | declare -gr bfl_aes_blue_reverse="\\033[7;34m" 234 | 235 | declare -gr bfl_aes_magenta="\\033[0;35m" 236 | declare -gr bfl_aes_magenta_bold="\\033[1;35m" 237 | declare -gr bfl_aes_magenta_faint="\\033[2;35m" 238 | declare -gr bfl_aes_magenta_underline="\\033[4;35m" 239 | declare -gr bfl_aes_magenta_blink="\\033[5;35m" 240 | declare -gr bfl_aes_magenta_reverse="\\033[7;35m" 241 | 242 | declare -gr bfl_aes_cyan="\\033[0;36m" 243 | declare -gr bfl_aes_cyan_bold="\\033[1;36m" 244 | declare -gr bfl_aes_cyan_faint="\\033[2;36m" 245 | declare -gr bfl_aes_cyan_underline="\\033[4;36m" 246 | declare -gr bfl_aes_cyan_blink="\\033[5;36m" 247 | declare -gr bfl_aes_cyan_reverse="\\033[7;36m" 248 | 249 | declare -gr bfl_aes_white="\\033[0;37m" 250 | declare -gr bfl_aes_white_bold="\\033[1;37m" 251 | declare -gr bfl_aes_white_faint="\\033[2;37m" 252 | declare -gr bfl_aes_white_underline="\\033[4;37m" 253 | declare -gr bfl_aes_white_blink="\\033[5;37m" 254 | declare -gr bfl_aes_white_reverse="\\033[7;37m" 255 | 256 | declare -gr bfl_aes_reset="\\033[0m" 257 | 258 | fi 259 | } 260 | 261 | bfl::declare_ansi_escape_sequences 262 | -------------------------------------------------------------------------------- /test/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------ 4 | # @file 5 | # Performs assertion testing of the functions in this library. 6 | # 7 | # This simple testing mechanism has no provision for the construction and 8 | # deconstruction of unit test scaffolding. Consequently, I am unable to provide 9 | # an affirmative assertion for bfl::is_apache_vhost. 10 | #------------------------------------------------------------------------------ 11 | 12 | #------------------------------------------------------------------------------ 13 | # @function 14 | # Declares assertions. 15 | # 16 | # Do not create any assertions for bfl::declare_ansi_escape_sequences because 17 | # the function declares readonly variables. Each assertion would fail due to 18 | # attempted assignments of readonly variables. 19 | # 20 | # @return global array $assertions 21 | # This is a one dimensional array. Each element is a pipe delimited list 22 | # of three values in this sequence: 23 | # 24 | # 1. Function to test (example: bfl::join) 25 | # 2. Parameters to pass to function (example, "1" "2" "3") 26 | # 3. Expected return code (example: 0) 27 | #------------------------------------------------------------------------------ 28 | declare_assertions() { 29 | declare -ga assertions=( 30 | 'bfl::die||1' 31 | 'bfl::die|""|1' 32 | 'bfl::die|" "|1' 33 | 'bfl::die|"foo"|1' 34 | 'bfl::die|"foo" "bar"|1' 35 | 36 | 'bfl::error||0' 37 | 'bfl::error|""|0' 38 | 'bfl::error|" "|0' 39 | 'bfl::error|"foo"|0' 40 | 'bfl::error|"foo" "bar"|1' 41 | 42 | 'bfl::find_nearest_integer||1' 43 | 'bfl::find_nearest_integer|"" "" ""|1' 44 | 'bfl::find_nearest_integer|"" ""|1' 45 | 'bfl::find_nearest_integer|" " " "|1' 46 | 'bfl::find_nearest_integer|"a" ""|1' 47 | 'bfl::find_nearest_integer|"1" ""|1' 48 | 'bfl::find_nearest_integer|"1" " "|1' 49 | 'bfl::find_nearest_integer|"1" "a e g"|1' 50 | 'bfl::find_nearest_integer|"1.1" "4 -1 0 1 4"|1' 51 | 'bfl::find_nearest_integer|"1" "4.1 -1 0 1 4"|1' 52 | 'bfl::find_nearest_integer|"-2" "-4 -1 0 1 4"|0' 53 | 'bfl::find_nearest_integer|"0" "-4 -1 0 1 4"|0' 54 | 'bfl::find_nearest_integer|"2" "-4 -1 0 1 4"|0' 55 | 56 | 'bfl::generate_password||1' 57 | 'bfl::generate_password|"" ""|1' 58 | 'bfl::generate_password|""|1' 59 | 'bfl::generate_password|" "|1' 60 | 'bfl::generate_password|"a"|1' 61 | 'bfl::generate_password|"1.1"|1' 62 | 'bfl::generate_password|"-1"|1' 63 | 'bfl::generate_password|"7"|1' 64 | 'bfl::generate_password|"8"|0' 65 | 66 | 'bfl::get_directory_path||1' 67 | 'bfl::get_directory_path|""|1' 68 | 'bfl::get_directory_path|" "|1' 69 | 'bfl::get_directory_path|"a" "b"|1' 70 | 'bfl::get_directory_path|"/tmp"|0' 71 | 'bfl::get_directory_path|"/tmp/non-existent-directory"|1' 72 | 'bfl::get_directory_path|"/etc/host.conf"|1' 73 | 74 | 'bfl::get_file_directory||1' 75 | 'bfl::get_file_directory|""|1' 76 | 'bfl::get_file_directory|" "|1' 77 | 'bfl::get_file_directory|"a" "b"|1' 78 | 'bfl::get_file_directory|"/tmp"|1' 79 | 'bfl::get_file_directory|"/tmp/non-existent-file.ext"|1' 80 | 'bfl::get_file_directory|"/etc/host.conf"|0' 81 | 82 | 'bfl::get_file_extension||1' 83 | 'bfl::get_file_extension|""|1' 84 | 'bfl::get_file_extension|" "|1' 85 | 'bfl::get_file_extension|"a" "b"|1' 86 | 'bfl::get_file_extension|"/tmp/non-existent-file.ext"|1' 87 | 'bfl::get_file_extension|"/etc/host.conf"|0' 88 | 89 | 'bfl::get_file_name_without_extension||1' 90 | 'bfl::get_file_name_without_extension|""|1' 91 | 'bfl::get_file_name_without_extension|" "|1' 92 | 'bfl::get_file_name_without_extension|"a" "b"|1' 93 | 'bfl::get_file_name_without_extension|"/tmp/non-existent-file.ext"|1' 94 | 'bfl::get_file_name_without_extension|"/etc/host.conf"|0' 95 | 96 | 'bfl::get_file_name||1' 97 | 'bfl::get_file_name|""|1' 98 | 'bfl::get_file_name|" "|1' 99 | 'bfl::get_file_name|"a" "b"|1' 100 | 'bfl::get_file_name|"/tmp/non-existent-file.ext"|1' 101 | 'bfl::get_file_name|"/etc/host.conf"|0' 102 | 103 | 'bfl::get_file_path||1' 104 | 'bfl::get_file_path|""|1' 105 | 'bfl::get_file_path|" "|1' 106 | 'bfl::get_file_path|"a" "b"|1' 107 | 'bfl::get_file_path|"/tmp/non-existent-file.ext"|1' 108 | 'bfl::get_file_path|"/etc/host.conf"|0' 109 | 110 | 'bfl::inform||0' 111 | 'bfl::inform|""|0' 112 | 'bfl::inform|" "|0' 113 | 'bfl::inform|"foo"|0' 114 | 'bfl::inform|"foo" "bar"|1' 115 | 116 | 'bfl::is_apache_vhost||1' 117 | 'bfl::is_apache_vhost|""|1' 118 | 'bfl::is_apache_vhost|"" ""|1' 119 | 'bfl::is_apache_vhost|" " " "|1' 120 | 'bfl::is_apache_vhost|"a" "b"|1' 121 | 'bfl::is_apache_vhost|"a"|1' 122 | 'bfl::is_apache_vhost|"a" " "|1' 123 | 'bfl::is_apache_vhost|"a" "b"|1' 124 | 'bfl::is_apache_vhost|"a" "/etc/apache2/sites-enabled"|1' 125 | 'bfl::is_apache_vhost|"/tmp" "b"|1' 126 | 127 | 'bfl::is_blank||1' 128 | 'bfl::is_blank|""|0' 129 | 'bfl::is_blank|" "|0' 130 | 'bfl::is_blank|"\t"|0' 131 | 'bfl::is_blank|"\n"|0' 132 | 'bfl::is_blank|"asd"|1' 133 | 134 | 'bfl::is_empty||1' 135 | 'bfl::is_empty|""|0' 136 | 'bfl::is_empty|" "|1' 137 | 'bfl::is_empty|"a"|1' 138 | 'bfl::is_empty|"a" "b"|1' 139 | 'bfl::is_empty|"" ""|1' 140 | 141 | 'bfl::is_integer||1' 142 | 'bfl::is_integer|""|1' 143 | 'bfl::is_integer|" "|1' 144 | 'bfl::is_integer|"foo"|1' 145 | 'bfl::is_integer|"1.2"|1' 146 | 'bfl::is_integer|"1" "2" "3"|1' 147 | 'bfl::is_integer|"-1"|0' 148 | 'bfl::is_integer|"1"|0' 149 | 150 | 'bfl::is_positive_integer||1' 151 | 'bfl::is_positive_integer|""|1' 152 | 'bfl::is_positive_integer|" "|1' 153 | 'bfl::is_positive_integer|"foo"|1' 154 | 'bfl::is_positive_integer|"1.2"|1' 155 | 'bfl::is_positive_integer|"1" "2" "3"|1' 156 | 'bfl::is_positive_integer|"-1"|1' 157 | 'bfl::is_positive_integer|"1"|0' 158 | 159 | 'bfl::join||1' 160 | 'bfl::join|","|1' 161 | 'bfl::join|"," "This is" "a" "test."|0' 162 | 'bfl::join|"," "Foo"|0' 163 | 'bfl::join|"" "Foo"|0' 164 | 'bfl::join|"" "" ""|0' 165 | 'bfl::join|"," ""|0' 166 | 'bfl::join|"," "" ""|0' 167 | 'bfl::join|"" ""|0' 168 | 169 | 'bfl::lorem|""|0' 170 | 'bfl::lorem|"0"|1' 171 | 'bfl::lorem|"-1"|1' 172 | 'bfl::lorem|"a"|1' 173 | 'bfl::lorem|"1" "darwin" "a"|1' 174 | 'bfl::lorem||0' 175 | 'bfl::lorem|"2"|0' 176 | 'bfl::lorem|"1" "burroughs" |0' 177 | 'bfl::lorem|"1" "darwin" |0' 178 | 'bfl::lorem|"1" "mills" |0' 179 | 'bfl::lorem|"1" "muir" |0' 180 | 'bfl::lorem|"1" "virgil" |0' 181 | 'bfl::lorem|"1" "xxx" |1' 182 | 183 | 'bfl::print_args||1' 184 | 'bfl::print_args|"foo"|0' 185 | 'bfl::print_args|""|0' 186 | 187 | 'bfl::repeat||1' 188 | 'bfl::repeat|"" "" ""|1' 189 | 'bfl::repeat|"" ""|1' 190 | 'bfl::repeat|"" " "|1' 191 | 'bfl::repeat|"" "a"|1' 192 | 'bfl::repeat|"" "1.1"|1' 193 | 'bfl::repeat|"" "-1"|1' 194 | 'bfl::repeat|"" "3"|0' 195 | 'bfl::repeat|" " "3"|0' 196 | 'bfl::repeat|"-" "3"|0' 197 | 198 | 'bfl::send_mail_msg||1' 199 | 'bfl::send_mail_msg|""|1' 200 | 'bfl::send_mail_msg|"" ""|1' 201 | 'bfl::send_mail_msg|"" "" ""|1' 202 | 'bfl::send_mail_msg|"" "" "" ""|1' 203 | 'bfl::send_mail_msg|"" "" "" "" ""|1' 204 | 'bfl::send_mail_msg|"" "" "" "" "" ""|1' 205 | 'bfl::send_mail_msg|"foo@example.com" "" "" "" ""|1' 206 | 'bfl::send_mail_msg|"foo@example.com" "foo@example.com" "" "" ""|1' 207 | 'bfl::send_mail_msg|"foo@example.com" "foo@example.com" "foo@example.com" "" ""|1' 208 | 'bfl::send_mail_msg|"foo@example.com" "foo@example.com" "foo@example.com" "Subject" ""|1' 209 | 'bfl::send_mail_msg|"foo@example.com" "foo@example.com" "foo@example.com" "Subject"|1' 210 | 'bfl::send_mail_msg|"foo@example.com" "foo@example.com" "foo@example.com" "Subject" "Body"|0' 211 | 'bfl::send_mail_msg|"Foo " "foo@example.com" "foo@example.com" "Subject" "Body"|0' 212 | 'bfl::send_mail_msg|"Foo " "Foo " "foo@example.com" "Subject" "Body"|0' 213 | 214 | 'bfl::send_sms_msg||1' 215 | 'bfl::send_sms_msg|""|1' 216 | 'bfl::send_sms_msg|"" ""|1' 217 | 'bfl::send_sms_msg|"foo"|1' 218 | 'bfl::send_sms_msg|"foo" ""|1' 219 | 'bfl::send_sms_msg|"foo" "bar"|1' 220 | 'bfl::send_sms_msg|"17039897379" "bar"|1' 221 | 'bfl::send_sms_msg|"+17039897379"|1' 222 | 'bfl::send_sms_msg|"+17039897379" ""|1' 223 | 'bfl::send_sms_msg|"+17039897379" "bar"|0' 224 | 225 | 'bfl::time_convert_s_to_hhmmss||1' 226 | 'bfl::time_convert_s_to_hhmmss|"" ""|1' 227 | 'bfl::time_convert_s_to_hhmmss|""|1' 228 | 'bfl::time_convert_s_to_hhmmss|" "|1' 229 | 'bfl::time_convert_s_to_hhmmss|"a"|1' 230 | 'bfl::time_convert_s_to_hhmmss|"1.1"|1' 231 | 'bfl::time_convert_s_to_hhmmss|"-1"|1' 232 | 'bfl::time_convert_s_to_hhmmss|"1"|0' 233 | 'bfl::time_convert_s_to_hhmmss|"61"|0' 234 | 'bfl::time_convert_s_to_hhmmss|"3661"|0' 235 | 236 | 'bfl::transliterate||1' 237 | 'bfl::transliterate|"This is A string." "So is this."|1' 238 | 'bfl::transliterate|""|0' 239 | 'bfl::transliterate|"This is A string."|0' 240 | 241 | 'bfl::trim||1' 242 | 'bfl::trim|""|0' 243 | 'bfl::trim|"abc"|0' 244 | 'bfl::trim|" def"|0' 245 | 'bfl::trim|"ghi "|0' 246 | 'bfl::trim|" jkl "|0' 247 | 'bfl::trim|" mno pqr stu "|0' 248 | 249 | 'bfl::urlencode||1' 250 | 'bfl::urlencode|""|1' 251 | 'bfl::urlencode|"" ""|1' 252 | 'bfl::urlencode|"a" "b"|1' 253 | 'bfl::urlencode|"foo bar"|0' 254 | 255 | 'bfl::verify_arg_count||1' 256 | 'bfl::verify_arg_count|"7"|1' 257 | 'bfl::verify_arg_count|"4" "5" "6"|1' 258 | 'bfl::verify_arg_count|"a" "8" "9"|1' 259 | 'bfl::verify_arg_count|"7" "b" "9"|1' 260 | 'bfl::verify_arg_count|"7" "8" "c"|1' 261 | 'bfl::verify_arg_count|"2" "1" "3"|0' 262 | 263 | 'bfl::verify_dependencies||1' 264 | 'bfl::verify_dependencies|"rm" "sort" "cough"|1' 265 | 'bfl::verify_dependencies|"rm" "ls" "whoami"|0' 266 | 267 | 'bfl::warn||0' 268 | 'bfl::warn|""|0' 269 | 'bfl::warn|" "|0' 270 | 'bfl::warn|"foo"|0' 271 | 'bfl::warn|"foo" "bar"|1' 272 | ) 273 | } 274 | 275 | #------------------------------------------------------------------------------ 276 | # @function 277 | # Tests a function to see if its return code matches the expected return code. 278 | # 279 | # @param string $function_to_test 280 | # The function to be tested. 281 | # @param string $args 282 | # The arguments to pass to the function. 283 | # @param string $expected_return_code 284 | # The expected return code (0 or 1). 285 | # 286 | # shellcheck disable=SC2059 287 | # shellcheck disable=SC2154 288 | #------------------------------------------------------------------------------ 289 | assert() { 290 | bfl::verify_arg_count "$#" 3 3 || exit 1 291 | 292 | declare -r function_to_test="$1" 293 | declare -r args="$2" 294 | declare -r expected_return_code="$3" 295 | declare actual_return_code 296 | declare cmd 297 | declare cmd_output 298 | declare format 299 | declare result 300 | 301 | # Test for empty strings. 302 | if bfl::is_empty "${function_to_test}"; then 303 | bfl::die "\$function_to_test is a an empty string." 304 | fi 305 | if bfl::is_empty "${expected_return_code}"; then 306 | bfl::die "\$expected_return_code is a an empty string." 307 | fi 308 | 309 | # Run the command. The command is run in a subshell (command substitution); 310 | # exit calls will terminate the subshell, not this script. 311 | cmd=$(printf "%s %s" "${function_to_test}" "${args}") 312 | cmd_output=$(eval "${cmd}" 2>&1) 313 | actual_return_code="$?" 314 | 315 | # Print results. 316 | if [[ "${actual_return_code}" -eq "${expected_return_code}" ]]; then 317 | result="PASS" 318 | format="${bfl_aes_green}%-${cw1}s${bfl_aes_reset} %-${cw2}s %-${cw3}s %-${cw4}s %-${cw5}s %-${cw6}s${bfl_aes_reset} \\n" 319 | else 320 | result="FAIL" 321 | format="${bfl_aes_red}%-${cw1}s${bfl_aes_reset} %-${cw2}s %-${cw3}s %-${cw4}s %-${cw5}s %-${cw6}s${bfl_aes_reset} \\n" 322 | fi 323 | cmd_output=${cmd_output//[$'\n']} 324 | printf "${format}" "${result}" "${function_to_test:0:${cw2}}" "${args:0:${cw3}}" "${expected_return_code}" "${actual_return_code}" "${cmd_output:0:${cw6}}" 325 | } 326 | 327 | #------------------------------------------------------------------------------ 328 | # @function 329 | # Main function. 330 | # 331 | # @param array global $assertions 332 | # Global array created by declare_assertions(). 333 | # 334 | # shellcheck disable=SC1090 335 | # shellcheck disable=SC2034 336 | # shellcheck disable=SC2059 337 | #------------------------------------------------------------------------------ 338 | main() { 339 | if ! source "${BASH_FUNCTION_LIBRARY}"; then 340 | printf "Error. Unable to source BASH_FUNCTION_LIBRARY.\\n" 1>&2 341 | exit 1 342 | fi 343 | 344 | # Declare assertions. 345 | declare_assertions 346 | 347 | # Declare column widths (global constants) for displaying test results. 348 | declare -rg cw1=6 # Width of column 1: Result (PASS/FAIL) 349 | declare -rg cw2=37 # Width of column 2: Function 350 | declare -rg cw3=33 # Width of column 3: Arguments 351 | declare -rg cw4=8 # Width of column 4: Expected return code 352 | declare -rg cw5=6 # Width of column 5: Actual return code 353 | declare -rg cw6=109 # Width of column 6: Command output 354 | 355 | # Declare other local variables. 356 | declare assertion 357 | declare -r format="%-${cw1}s %-${cw2}s %-${cw3}s %-${cw4}s %-${cw5}s %-${cw6}s" 358 | declare line_1 line_2 line_3 line_4 line_5 line_6 359 | declare -a pieces 360 | 361 | # Create table header lines for for displaying test results. 362 | line_1=$(bfl::repeat "=" ${cw1}) 363 | line_2=$(bfl::repeat "=" ${cw2}) 364 | line_3=$(bfl::repeat "=" ${cw3}) 365 | line_4=$(bfl::repeat "=" ${cw4}) 366 | line_5=$(bfl::repeat "=" ${cw5}) 367 | line_6=$(bfl::repeat "=" ${cw6}) 368 | 369 | # Clear the screen. 370 | clear 371 | 372 | # Print initial newline. 373 | printf "\\n" 374 | 375 | # Print table header. 376 | printf "${format}\\n" "" "" "" "Expected" "Actual" "" 377 | printf "${format}\\n" "" "" "" "Return" "Return" "" 378 | printf "${format}\\n" "Result" "Function" "Arguments (truncated)" "Code" "Code" "First line of command output (truncated)" 379 | printf "%s %s %s %s %s %s\\n" "${line_1}" "${line_2}" "${line_3}" "${line_4}" "${line_5}" "${line_6}" 380 | 381 | # Run assertion tests. 382 | for assertion in "${assertions[@]}"; do 383 | IFS="|" read -r -a pieces <<< "${assertion}" 384 | # ${pieces[0]} is the function to be called 385 | # ${pieces[1]} is the arguments string 386 | # ${pieces[2]} is the expected return code 387 | assert "${pieces[0]}" "${pieces[1]}" "${pieces[2]}" || true 388 | done 389 | 390 | # Print final newline. 391 | printf "\\n" 392 | } 393 | 394 | set -euo pipefail 395 | main 396 | -------------------------------------------------------------------------------- /docs/function-list.md: -------------------------------------------------------------------------------- 1 | # Bash Function Library 2 | 3 | ## Function List 4 | 5 | * [bfl::declare_ansi_escape_sequences](#bfldeclare_ansi_escape_sequences) 6 | * [bfl::die](#bfldie) 7 | * [bfl::error](#bflerror) 8 | * [bfl::find_nearest_integer](#bflfind_nearest_integer) 9 | * [bfl::generate_password](#bflgenerate_password) 10 | * [bfl::get_directory_path](#bflget_directory_path) 11 | * [bfl::get_file_directory](#bflget_file_directory) 12 | * [bfl::get_file_extension](#bflget_file_extension) 13 | * [bfl::get_file_name](#bflget_file_name) 14 | * [bfl::get_file_name_without_extension](#bflget_file_name_without_extension) 15 | * [bfl::get_file_path](#bflget_file_path) 16 | * [bfl::inform](#bflinform) 17 | * [bfl::is_apache_vhost](#bflis_apache_vhost) 18 | * [bfl::is_blank](#bflis_blank) 19 | * [bfl::is_empty](#bflis_empty) 20 | * [bfl::is_integer](#bflis_integer) 21 | * [bfl::is_positive_integer](#bflis_positive_integer) 22 | * [bfl::join](#bfljoin) 23 | * [bfl::lorem](#bfllorem) 24 | * [bfl::print_args](#bflprint_args) 25 | * [bfl::repeat](#bflrepeat) 26 | * [bfl::send_mail_msg](#bflsend_mail_msg) 27 | * [bfl::send_sms_msg](#bflsend_sms_msg) 28 | * [bfl::time_convert_s_to_hhmmss](#bfltime_convert_s_to_hhmmss) 29 | * [bfl::transliterate](#bfltransliterate) 30 | * [bfl::trim](#bfltrim) 31 | * [bfl::urlencode](#bflurlencode) 32 | * [bfl::verify_arg_count](#bflverify_arg_count) 33 | * [bfl::verify_dependencies](#bflverify_dependencies) 34 | * [bfl::warn](#bflwarn) 35 | 36 | ## bfl::declare_ansi_escape_sequences 37 | 38 | Declares ANSI escape sequences. 39 | 40 | **Returns** 41 | 42 | global string $bfl_aes_black 43 | >ANSI escape sequence for black. 44 | 45 | global string $bfl_aes_black_bold 46 | >ANSI escape sequence for black + bold. 47 | 48 | global string $bfl_aes_black_faint 49 | >ANSI escape sequence for black + faint. 50 | 51 | global string $bfl_aes_black_underline 52 | >ANSI escape sequence for black + underline. 53 | 54 | global string $bfl_aes_black_blink 55 | >ANSI escape sequence for black + blink. 56 | 57 | global string $bfl_aes_black_reverse 58 | >ANSI escape sequence for black + reverse. 59 | 60 | global string $bfl_aes_red 61 | >ANSI escape sequence for red. 62 | 63 | global string $bfl_aes_red_bold 64 | >ANSI escape sequence for red + bold. 65 | 66 | global string $bfl_aes_red_faint 67 | >ANSI escape sequence for red + faint. 68 | 69 | global string $bfl_aes_red_underline 70 | >ANSI escape sequence for red + underline. 71 | 72 | global string $bfl_aes_red_blink 73 | >ANSI escape sequence for red + blink. 74 | 75 | global string $bfl_aes_red_reverse 76 | >ANSI escape sequence for red + reverse. 77 | 78 | global string $bfl_aes_green 79 | >ANSI escape sequence for green. 80 | 81 | global string $bfl_aes_green_bold 82 | >ANSI escape sequence for green + bold. 83 | 84 | global string $bfl_aes_green_faint 85 | >ANSI escape sequence for green + faint. 86 | 87 | global string $bfl_aes_green_underline 88 | >ANSI escape sequence for green + underline. 89 | 90 | global string $bfl_aes_green_blink 91 | >ANSI escape sequence for green + blink. 92 | 93 | global string $bfl_aes_green_reverse 94 | >ANSI escape sequence for green + reverse. 95 | 96 | global string $bfl_aes_yellow 97 | >ANSI escape sequence for yellow. 98 | 99 | global string $bfl_aes_yellow_bold 100 | >ANSI escape sequence for yellow + bold. 101 | 102 | global string $bfl_aes_yellow_faint 103 | >ANSI escape sequence for yellow + faint. 104 | 105 | global string $bfl_aes_yellow_underline 106 | >ANSI escape sequence for yellow + underline. 107 | 108 | global string $bfl_aes_yellow_blink 109 | >ANSI escape sequence for yellow + blink. 110 | 111 | global string $bfl_aes_yellow_reverse 112 | >ANSI escape sequence for yellow + reverse. 113 | 114 | global string $bfl_aes_blue 115 | >ANSI escape sequence for blue. 116 | 117 | global string $bfl_aes_blue_bold 118 | >ANSI escape sequence for blue + bold. 119 | 120 | global string $bfl_aes_blue_faint 121 | >ANSI escape sequence for blue + faint. 122 | 123 | global string $bfl_aes_blue_underline 124 | >ANSI escape sequence for blue + underline. 125 | 126 | global string $bfl_aes_blue_blink 127 | >ANSI escape sequence for blue + blink. 128 | 129 | global string $bfl_aes_blue_reverse 130 | >ANSI escape sequence for blue + reverse. 131 | 132 | global string $bfl_aes_magenta 133 | >ANSI escape sequence for magenta. 134 | 135 | global string $bfl_aes_magenta_bold 136 | >ANSI escape sequence for magenta + bold. 137 | 138 | global string $bfl_aes_magenta_faint 139 | >ANSI escape sequence for magenta + faint. 140 | 141 | global string $bfl_aes_magenta_underline 142 | >ANSI escape sequence for magenta + underline. 143 | 144 | global string $bfl_aes_magenta_blink 145 | >ANSI escape sequence for magenta + blink. 146 | 147 | global string $bfl_aes_magenta_reverse 148 | >ANSI escape sequence for magenta + reverse. 149 | 150 | global string $bfl_aes_cyan 151 | >ANSI escape sequence for cyan. 152 | 153 | global string $bfl_aes_cyan_bold 154 | >ANSI escape sequence for cyan + bold. 155 | 156 | global string $bfl_aes_cyan_faint 157 | >ANSI escape sequence for cyan + faint. 158 | 159 | global string $bfl_aes_cyan_underline 160 | >ANSI escape sequence for cyan + underline. 161 | 162 | global string $bfl_aes_cyan_blink 163 | >ANSI escape sequence for cyan + blink. 164 | 165 | global string $bfl_aes_cyan_reverse 166 | >ANSI escape sequence for cyan + reverse. 167 | 168 | global string $bfl_aes_white 169 | >ANSI escape sequence for white. 170 | 171 | global string $bfl_aes_white_bold 172 | >ANSI escape sequence for white + bold. 173 | 174 | global string $bfl_aes_white_faint 175 | >ANSI escape sequence for white + faint. 176 | 177 | global string $bfl_aes_white_underline 178 | >ANSI escape sequence for white + underline. 179 | 180 | global string $bfl_aes_white_blink 181 | >ANSI escape sequence for white + blink. 182 | 183 | global string $bfl_aes_white_reverse 184 | >ANSI escape sequence for white + reverse. 185 | 186 | **Example** 187 | 188 | ```bash 189 | bfl::declare_ansi_escape_sequences 190 | ``` 191 | 192 | ## bfl::die 193 | 194 | Prints a fatal error message to stderr, then exits with status code 1. 195 | 196 | **Parameter** 197 | 198 | string $msg (optional) 199 | >The message. 200 | 201 | **Example** 202 | 203 | ```bash 204 | bfl::error "The foo is bar." 205 | ``` 206 | 207 | ## bfl::error 208 | 209 | Prints an error message to stderr. 210 | 211 | **Parameter** 212 | 213 | string $msg (optional) 214 | >The message. 215 | 216 | **Example** 217 | 218 | ```bash 219 | bfl::error "The foo is bar." 220 | ``` 221 | 222 | ## bfl::find_nearest_integer 223 | 224 | Finds the nearest integer to a target integer from a list of integers. 225 | 226 | **Parameters** 227 | 228 | string $target 229 | >The target integer. 230 | 231 | string $list 232 | >A list of integers. 233 | 234 | **Return** 235 | 236 | string $nearest 237 | >Integer in list that is nearest to the target. 238 | 239 | **Example** 240 | 241 | ```bash 242 | bfl::find_nearest_integer "4" "0 3 6 9 12" 243 | ``` 244 | 245 | ## bfl::generate_password 246 | 247 | Generates a random password. 248 | 249 | **Parameter** 250 | 251 | int $pswd_length 252 | >The length of the desired password. 253 | 254 | **Return** 255 | 256 | string $password 257 | >A random password 258 | 259 | **Example** 260 | 261 | ```bash 262 | bfl::generate_password "16" 263 | ``` 264 | 265 | ## bfl::get_directory_path 266 | 267 | Gets the canonical path to a directory. 268 | 269 | **Parameter** 270 | 271 | string $path 272 | >A relative path, absolute path, or symbolic link. 273 | 274 | **Return** 275 | 276 | string $canonical_directory_path 277 | >The canonical path to the directory. 278 | 279 | **Example** 280 | 281 | ```bash 282 | bfl::get_directory_path "./foo" 283 | ``` 284 | 285 | ## bfl::get_file_directory 286 | 287 | Gets the canonical path to the directory in which a file resides. 288 | 289 | **Parameter** 290 | 291 | string $path 292 | >A relative path, absolute path, or symbolic link. 293 | 294 | **Return** 295 | 296 | string $canonical_directory_path 297 | >The canonical path to the directory in which a file resides. 298 | 299 | **Example** 300 | 301 | ```bash 302 | bfl::get_file_directory "./foo/bar.txt" 303 | ``` 304 | 305 | ## bfl::get_file_extension 306 | 307 | Gets the file extension. 308 | 309 | **Parameter** 310 | 311 | string $path 312 | >A relative path, absolute path, or symbolic link. 313 | 314 | **Return** 315 | 316 | string $file_extension 317 | >The file extension, excluding the preceding period. 318 | 319 | **Example** 320 | 321 | ```bash 322 | bfl::get_file_extension "./foo/bar.txt" 323 | ``` 324 | 325 | ## bfl::get_file_name 326 | 327 | Gets the file name, including extension. 328 | 329 | **Parameter** 330 | 331 | string $path 332 | >A relative path, absolute path, or symbolic link. 333 | 334 | **Return** 335 | 336 | string $file_name 337 | >The file name, including extension. 338 | 339 | **Example** 340 | 341 | ```bash 342 | bfl::get_file_name "./foo/bar.text" 343 | ``` 344 | 345 | ## bfl::get_file_name_without_extension 346 | 347 | Gets the file name, excluding extension. 348 | 349 | **Parameter** 350 | 351 | string $path 352 | >A relative path, absolute path, or symbolic link. 353 | 354 | **Return** 355 | 356 | string $file_name_without_extension 357 | >The file name, excluding extension. 358 | 359 | **Example** 360 | 361 | ```bash 362 | bfl::get_file_name_without_extension "./foo/bar.txt" 363 | ``` 364 | 365 | ## bfl::get_file_path 366 | 367 | Gets the canonical path to a file. 368 | 369 | **Parameter** 370 | 371 | string $path 372 | >A relative path, absolute path, or symbolic link. 373 | 374 | **Return** 375 | 376 | string $canonical_file_path 377 | >The canonical path to the file. 378 | 379 | **Example** 380 | 381 | ```bash 382 | bfl::get_file_path "./foo/bar.text" 383 | ``` 384 | 385 | ## bfl::inform 386 | 387 | Prints an informational message to stderr. 388 | 389 | **Parameter** 390 | 391 | string $msg (optional) 392 | >The message. A blank line will be printed if no message is provided. 393 | 394 | **Example** 395 | 396 | ```bash 397 | bfl::inform "The foo is bar." 398 | ``` 399 | 400 | ## bfl::is_apache_vhost 401 | 402 | Checks if the given path is the root of an Apache virtual host. 403 | 404 | **Parameters** 405 | 406 | string $path 407 | >A relative path, absolute path, or symbolic link. 408 | 409 | string $sites_enabled [optional] 410 | >Absolute path to Apache's "sites-enabled" directory. 411 | 412 | **Examples** 413 | 414 | ```bash 415 | bfl::is_apache_vhost "./foo" 416 | bfl::is_apache_vhost "./foo" "/etc/apache2/sites-enabled" 417 | ``` 418 | 419 | ## bfl::is_blank 420 | 421 | Checks if a string is whitespace, empty (""), or null. 422 | 423 | **Parameter** 424 | 425 | string $str 426 | >The string to check. 427 | 428 | **Example** 429 | 430 | ```bash 431 | bfl::is_blank "foo" 432 | ``` 433 | 434 | ## bfl::is_empty 435 | 436 | Checks if a string is empty ("") or null. 437 | 438 | **Parameter** 439 | 440 | string $str 441 | >The string to check. 442 | 443 | **Example** 444 | 445 | ```bash 446 | bfl::is_empty "foo" 447 | ``` 448 | 449 | ## bfl::is_integer 450 | 451 | Determines if the argument is an integer. 452 | 453 | **Parameter** 454 | 455 | string $value_to_test 456 | >The value to be tested. 457 | 458 | **Example** 459 | 460 | ```bash 461 | bfl::is_integer "8675309" 462 | ``` 463 | 464 | ## bfl::is_positive_integer 465 | 466 | Determines if the argument is a positive integer. 467 | 468 | **Parameter** 469 | 470 | string $value_to_test 471 | >The value to be tested. 472 | 473 | **Example** 474 | 475 | ```bash 476 | bfl::is_positive_integer "8675309" 477 | ``` 478 | 479 | ## bfl::join 480 | 481 | Joins multiple strings into a single string, separated by another string. 482 | 483 | **Parameters** 484 | 485 | string $glue 486 | >The character or characters that will be used to glue the strings together. 487 | 488 | list $pieces 489 | >The list of strings to be combined. 490 | 491 | **Return** 492 | 493 | string $joined_string 494 | >The joined string. 495 | 496 | **Example** 497 | 498 | ```bash 499 | bfl::join "," "foo" "bar" "baz" 500 | ``` 501 | 502 | ## bfl::lorem 503 | 504 | Randomly extracts one or more sequential paragraphs from a given resource. 505 | 506 | **Parameters** 507 | 508 | int $paragraphs (optional) 509 | >The number of paragraphs to extract (default: 1). 510 | 511 | string $resource (optional) 512 | >The resource from which to extract the paragraphs (default: muir). 513 | 514 | **Return** 515 | 516 | string $text 517 | >The extracted paragraphs. 518 | 519 | **Examples** 520 | 521 | ```bash 522 | bfl::lorem 523 | bfl::lorem 2 524 | bfl::lorem 3 burroughs 525 | bfl::lorem 3 darwin 526 | bfl::lorem 3 mills 527 | bfl::lorem 3 muir 528 | bfl::lorem 3 virgil 529 | ``` 530 | 531 | ## bfl::print_args 532 | 533 | Prints the arguments passed to this function. 534 | 535 | **Parameter** 536 | 537 | list $arguments 538 | >One or more arguments. 539 | 540 | **Example** 541 | 542 | ```bash 543 | bfl::print_args "foo" "bar" "baz" 544 | ``` 545 | 546 | ## bfl::repeat 547 | 548 | Repeats a string. 549 | 550 | **Parameters** 551 | 552 | string $str 553 | >The string to be repeated. 554 | 555 | int $multiplier 556 | >Number of times the string will be repeated. 557 | 558 | **Return** 559 | 560 | string $str_repeated 561 | >The repeated string. 562 | 563 | **Example** 564 | 565 | ```bash 566 | bfl::repeat "=" "10" 567 | ``` 568 | 569 | ## bfl::send_mail_msg 570 | 571 | Sends an email message via sendmail. 572 | 573 | **Parameters** 574 | 575 | string $to 576 | >Message recipient or recipients. 577 | 578 | string $from 579 | >Message sender. 580 | 581 | string $envelope_from 582 | >Envelope sender address. 583 | 584 | string $subject 585 | >Message subject. 586 | 587 | string $body 588 | >Message body. 589 | 590 | **Example** 591 | 592 | ```bash 593 | bfl::send_mail_msg "a@b.com" "x@y.com" "x@y.com" "Test" "Line 1.\nLine 2." 594 | ``` 595 | 596 | ## bfl::send_sms_msg 597 | 598 | Sends an SMS message via Amazon Simple Notification Service (SNS). 599 | 600 | **Parameters** 601 | 602 | string $phone_number 603 | >Recipient's phone number, including country code. 604 | 605 | string $message 606 | >Example: "This is line one.\nThis is line two.\n" 607 | 608 | **Example** 609 | 610 | ```bash 611 | bfl::send_sms_msg "+12065550100" "Line 1.\nLine 2." 612 | ``` 613 | 614 | ## bfl::time_convert_s_to_hhmmss 615 | 616 | Converts seconds to the hh:mm:ss format. 617 | 618 | **Parameter** 619 | 620 | int $seconds 621 | >The number of seconds to convert. 622 | 623 | **Return** 624 | 625 | string $hhmmss 626 | >The number of seconds in hh:mm:ss format. 627 | 628 | **Example** 629 | 630 | ```bash 631 | bfl::time_convert_s_to_hhmmss "3661" 632 | ``` 633 | 634 | ## bfl::transliterate 635 | 636 | Transliterates a string. 637 | 638 | **Parameter** 639 | 640 | string $str 641 | >The string to transliterate. 642 | 643 | **Return** 644 | 645 | string $str_transliterated 646 | >The transliterated string. 647 | 648 | **Example** 649 | 650 | ```bash 651 | bfl::transliterate "_Olé Über! " 652 | ``` 653 | 654 | ## bfl::trim 655 | 656 | Removes leading and trailing whitespace, including blank lines, from string. 657 | 658 | **Parameter** 659 | 660 | string $str 661 | >The string to be trimmed. 662 | 663 | **Return** 664 | 665 | string $str_trimmed 666 | >The trimmed string. 667 | 668 | **Example** 669 | 670 | ```bash 671 | bfl::trim " foo " 672 | ``` 673 | 674 | ## bfl::urlencode 675 | 676 | Percent-encodes a URL. 677 | 678 | **Parameter** 679 | 680 | string $str 681 | >The string to be encoded. 682 | 683 | **Return** 684 | 685 | string $str_encoded 686 | >The encoded string. 687 | 688 | **Example** 689 | 690 | ```bash 691 | bfl::urlencode "foo bar" 692 | ``` 693 | 694 | ## bfl::verify_arg_count 695 | 696 | Verifies the number of arguments received against expected values. 697 | 698 | **Parameters** 699 | 700 | int $actual_arg_count 701 | >Actual number of arguments received. 702 | 703 | int $expected_arg_count_min 704 | >Minimum number of arguments expected. 705 | 706 | int $expected_arg_count_max 707 | >Maximum number of arguments expected. 708 | 709 | **Example** 710 | 711 | ```bash 712 | bfl::verify_arg_count "$#" 2 3 713 | ``` 714 | 715 | ## bfl::verify_dependencies 716 | 717 | Verifies that dependencies are installed. 718 | 719 | **Parameter** 720 | 721 | array $apps 722 | >One dimensional array of applications, executables, or commands. 723 | 724 | **Example** 725 | 726 | ```bash 727 | bfl::verify_dependencies "curl" "wget" "git" 728 | ``` 729 | 730 | ## bfl::warn 731 | 732 | Prints a warning message to stderr. 733 | 734 | **Parameter** 735 | 736 | string $msg (optional) 737 | >The message. 738 | 739 | **Example** 740 | 741 | ```bash 742 | bfl::warn "The foo is bar." 743 | ``` 744 | 745 | --- 746 | *Last updated: 2020-06-20T15:38:20-04:00.* 747 | --------------------------------------------------------------------------------