# Functions for manipulating arrays _dedupeArray_() { # DESC: # Removes duplicate array elements # ARGS: # $1 (Required) - Input array # OUTS: # stdout: Prints de-duped elements # USAGE: # mapfile -t newarray < <(_dedupeArray_ "${array[@]}") # NOTE: # List order may not stay the same # CREDIT: # https://github.com/dylanaraps/pure-bash-bible [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" declare -A _tmpArray declare -a _uniqueArray local _i for _i in "$@"; do { [[ -z ${_i} || -n ${_tmpArray[${_i}]:-} ]]; } && continue _uniqueArray+=("${_i}") && _tmpArray[${_i}]=x done printf '%s\n' "${_uniqueArray[@]}" } _forEachDo_() { # DESC: # Iterates over elements and passes each to a function # ARGS: # $1 (Required) - Function name to pass each item to # OUTS: # 0 - Success # Return code of called function # stdout: Output of called function # USAGE: # printf "%s\n" "${arr1[@]}" | _forEachDo_ "test_func" # _forEachDo_ "test_func" < <(printf "%s\n" "${arr1[@]}") #alternative approach # CREDIT: # https://github.com/labbots/bash-utility [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local _func="${1}" local IFS=$'\n' local _it while read -r _it; do if [[ ${_func} == *"$"* ]]; then eval "${_func}" else if declare -f "${_func}" &>/dev/null; then eval "${_func}" "'${_it}'" else fatal "${FUNCNAME[0]} could not find function ${_func}" fi fi declare -i _ret="$?" if [[ ${_ret} -ne 0 ]]; then return "${_ret}" fi done } _forEachValidate_() { # DESC: # Iterates over elements and passes each to a function for validation. Iteration stops when the function returns 1. # ARGS: # $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success) # OUTS: # 0 - Success # 1 - Iteratee function fails # USAGE: # printf "%s\n" "${array[@]}" | _forEachValidate_ "_isAlpha_" # _forEachValidate_ "_isAlpha_" < <(printf "%s\n" "${array[@]}") # CREDIT: # https://github.com/labbots/bash-utility [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local _func="${1}" local IFS=$'\n' local _it while read -r _it; do if [[ ${_func} == *"$"* ]]; then eval "${_func}" else if ! declare -f "${_func}"; then fatal "${FUNCNAME[0]} could not find function ${_func}" else eval "${_func}" "'${_it}'" fi fi declare -i _ret="$?" if [[ ${_ret} -ne 0 ]]; then return 1 fi done } _forEachFind_() { # DESC: # Iterates over elements, returning success and printing the first value that is validated by a function # ARGS: # $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success) # OUTS: # 0 - If successful # 1 - If iteratee function fails # stdout: First value that is validated by the function # USAGE: # printf "%s\n" "${array[@]}" | _forEachFind_ "_isAlpha_" # _forEachFind_ "_isAlpha_" < <(printf "%s\n" "${array[@]}") # CREDIT: # https://github.com/labbots/bash-utility [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" declare _func="${1}" declare IFS=$'\n' while read -r _it; do if [[ ${_func} == *"$"* ]]; then eval "${_func}" else eval "${_func}" "'${_it}'" fi declare -i _ret="$?" if [[ ${_ret} == 0 ]]; then printf "%s" "${_it}" return 0 fi done return 1 } _forEachFilter_() { # DESC: # Iterates over elements, returning only those that are validated by a function # ARGS: # $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success) # OUTS: # 0 - Success # 1 - Failure # stdout: Values matching the validation function # USAGE: # printf "%s\n" "${array[@]}" | _forEachFind_ "_isAlpha_" # _forEachFilter_ "_isAlpha_" < <(printf "%s\n" "${array[@]}") # CREDIT: # https://github.com/labbots/bash-utility [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local _func="${1}" local IFS=$'\n' while read -r _it; do if [[ ${_func} == *"$"* ]]; then eval "${_func}" else eval "${_func}" "'${_it}'" fi declare -i _ret="$?" if [[ ${_ret} == 0 ]]; then printf "%s\n" "${_it}" fi done } _forEachReject_() { # DESC: # The opposite of _forEachFilter_. Iterates over elements, returning only those that are not validated by a function # ARGS: # $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success, 1 on failure) # OUTS: # 0 - Success # stdout: Values NOT matching the validation function # USAGE: # printf "%s\n" "${array[@]}" | _forEachReject_ "_isAlpha_" # _forEachReject_ "_isAlpha_" < <(printf "%s\n" "${array[@]}") # CREDIT: # https://github.com/labbots/bash-utility [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local _func="${1}" local IFS=$'\n' while read -r _it; do if [[ ${_func} == *"$"* ]]; then eval "${_func}" else eval "${_func}" "'${_it}'" fi declare -i _ret=$? if [[ ${_ret} -ne 0 ]]; then printf "%s\n" "${_it}" fi done } _forEachSome_() { # DESC: # Iterates over elements, returning true if any of the elements validate as true from the function. # ARGS: # $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success, 1 on failure) # OUTS: # 0 If match successful # 1 If no match found # USAGE: # printf "%s\n" "${array[@]}" | _forEachSome_ "_isAlpha_" # _forEachSome_ "_isAlpha_" < <(printf "%s\n" "${array[@]}") # CREDIT: # https://github.com/labbots/bash-utility [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local _func="${1}" local IFS=$'\n' while read -r _it; do if [[ ${_func} == *"$"* ]]; then eval "${_func}" else eval "${_func}" "'${_it}'" fi declare -i _ret=$? if [[ ${_ret} -eq 0 ]]; then return 0 fi done return 1 } _inArray_() { # DESC: # Determine if a regex matches an array element. Default is case sensitive. # Pass -i flag to ignore case. # ARGS: # $1 (Required) - Value to search for # $2 (Required) - Array written as ${ARRAY[@]} # OPTIONS: # -i (Optional) - Ignore case # OUTS: # 0 if true # 1 if untrue # USAGE: # if _inArray_ "VALUE" "${ARRAY[@]}"; then ... # if _inArray_ -i "VALUE" "${ARRAY[@]}"; then ... # CREDIT: # https://github.com/labbots/bash-utility [[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local opt local OPTIND=1 while getopts ":iI" opt; do case ${opt} in i | I) #shellcheck disable=SC2064 trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits shopt -s nocasematch # Use case-insensitive regex ;; *) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;; esac done shift $((OPTIND - 1)) local _array_item local _value="${1}" shift for _array_item in "$@"; do [[ ${_array_item} =~ ^${_value}$ ]] && return 0 done return 1 } _isEmptyArray_() { # DESC: # Checks if an array is empty # ARGS: # $1 (Required) - Input array # OUTS: # 0 if empty # 1 if not empty # USAGE: # _isEmptyArray_ "${array[@]}" # CREDIT: # https://github.com/labbots/bash-utility [ ${#@} -eq 0 ] } _joinArray_() { # DESC: # Joins items together with a user specified separator # ARGS: # $1 (Required) - Separator # $@ (Required) - Array or space separated items to be joined # OUTS: # stdout: Prints joined terms # USAGE: # _joinArray_ , a "b c" d #a,b c,d # _joinArray_ / var local tmp #var/local/tmp # _joinArray_ , "${foo[@]}" #a,b,c # CREDIT: # http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array # https://github.com/labbots/bash-utility [[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local _delimiter="${1}" shift printf "%s" "${1}" shift printf "%s" "${@/#/${_delimiter}}" } _mergeArrays_() { # DESC: # Merges two arrays together # ARGS: # $1 (Required) - Array 1 # $2 (Required) - Array 2 # OUTS: # stdout: Prints result # USAGE: # newarray=($(_mergeArrays_ "array1[@]" "array2[@]")) # NOTE: # Note that the arrays must be passed in as strings # CREDIT: # https://github.com/labbots/bash-utility [[ $# -ne 2 ]] && fatal 'Missing required argument to _mergeArrays_' declare -a _arr1=("${!1}") declare -a _arr2=("${!2}") declare _outputArray=("${_arr1[@]}" "${_arr2[@]}") printf "%s\n" "${_outputArray[@]}" } _reverseSortArray_() { # DESC: # Sorts an array from lowest to highest (z-a9-0) # ARGS: # $1 (Required) - Input array # OUTS: # stdout: Prints result # USAGE: # _reverseSortArray_ "${array[@]}" # NOTE: # input=("c" "b" "4" "1" "2" "3" "a") # _reverseSortArray_ "${input[@]}" # c b a 4 3 2 1 # CREDIT: # https://github.com/labbots/bash-utility [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" declare -a _array=("$@") declare -a _sortedArray mapfile -t _sortedArray < <(printf '%s\n' "${_array[@]}" | sort -r) printf "%s\n" "${_sortedArray[@]}" } _randomArrayElement_() { # DESC: # Selects a random item from an array # ARGS: # $1 (Required) - Input array # OUTS: # stdout: Prints one random element # USAGE: # _randomArrayElement_ "${array[@]}" # CREDIT: # https://github.com/dylanaraps/pure-bash-bible [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" declare -a _array local _array=("$@") printf '%s\n' "${_array[RANDOM % $#]}" } _setDiff_() { # DESC: # Return items that exist in ARRAY1 that are do not exist in ARRAY2 # ARGS: # $1 (Required) - Array 1 (in format ARRAY[@]) # $2 (Required) - Array 2 (in format ARRAY[@]) # OUTS: # 0 if unique elements found # 1 if arrays are the same # stdout: Prints unique elements # USAGE: # _setDiff_ "array1[@]" "array2[@]" # mapfile -t NEW_ARRAY < <(_setDiff_ "array1[@]" "array2[@]") # NOTE: # Note that the arrays must be passed in as strings # CREDIT: # http://stackoverflow.com/a/1617303/142339 [[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" local _skip local _a local _b declare -a _setdiffA=("${!1}") declare -a _setdiffB=("${!2}") declare -a _setdiffC=() for _a in "${_setdiffA[@]}"; do _skip=0 for _b in "${_setdiffB[@]}"; do if [[ ${_a} == "${_b}" ]]; then _skip=1 break fi done [[ ${_skip} -eq 1 ]] || _setdiffC=("${_setdiffC[@]}" "${_a}") done if [[ ${#_setdiffC[@]} == 0 ]]; then return 1 else printf "%s\n" "${_setdiffC[@]}" fi } _sortArray_() { # DESC: # Sorts an array from lowest to highest (0-9 a-z) # ARGS: # $1 (Required) - Input array # OUTS: # stdout: Prints result # USAGE: # _sortArray_ "${array[@]}" # NOTE: # input=("c" "b" "4" "1" "2" "3" "a") # _sortArray_ "${input[@]}" # 1 2 3 4 a b c # CREDIT: # https://github.com/labbots/bash-utility [[ $# -eq 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" declare -a _array=("$@") declare -a _sortedArray mapfile -t _sortedArray < <(printf '%s\n' "${_array[@]}" | sort) printf "%s\n" "${_sortedArray[@]}" }