diff --git a/bin/.local/share/lib/utilFunctions.sh b/bin/.local/share/lib/utilFunctions.sh new file mode 100644 index 00000000..25610573 --- /dev/null +++ b/bin/.local/share/lib/utilFunctions.sh @@ -0,0 +1,760 @@ +#!/usr/bin/env bash + +# ################################################## +# Bash scripting Utilities. +# +# This script sources my collection of scripting utilities making +# it possible to source this one script and gain access to a +# complete collection of functions, variables, and other options. +# +# Initially taken from here: https://github.com/natelandau/shell-scripts/blob/master/lib/utils.sh +# +# ################################################## + +# Logging and Colors +# ------------------------------------------------------ +# Here we set the colors for our script feedback. +# Example usage: success "sometext" +#------------------------------------------------------ + +# Set Colors +bold=$(tput bold) +underline=$(tput sgr 0 1) +reset=$(tput sgr0) +purple=$(tput setaf 171) +red=$(tput setaf 1) +green=$(tput setaf 76) +tan=$(tput setaf 3) +blue=$(tput setaf 38) + +function _alert() { + if [ "${1}" = "emergency" ]; then + local color="${bold}${red}" + fi + if [ "${1}" = "error" ]; then local color="${bold}${red}"; fi + if [ "${1}" = "warning" ]; then local color="${red}"; fi + if [ "${1}" = "success" ]; then local color="${green}"; fi + if [ "${1}" = "debug" ]; then local color="${purple}"; fi + if [ "${1}" = "header" ]; then local color="${bold}""${tan}"; fi + if [ "${1}" = "input" ]; then local color="${bold}"; printLog="false"; fi + if [ "${1}" = "info" ] || [ "${1}" = "notice" ]; then local color=""; fi + # Don't use colors on pipes or non-recognized terminals + if [[ "${TERM}" != "xterm"* ]] || [ -t 1 ]; then color=""; reset=""; fi + + # Print to $logFile + if [[ ${printLog} = "true" ]] || [ "${printLog}" == "1" ]; then + echo -e "$(date +"%m-%d-%Y %r") $(printf "[%9s]" "${1}") ${_message}" >> "${logFile}"; + fi + + # Print to console when script is not 'quiet' + if [[ "${quiet}" = "true" ]] || [ "${quiet}" == "1" ]; then + return + else + echo -e "$(date +"%r") ${color}$(printf "[%9s]" "${1}") ${_message}${reset}"; + fi + +} + +function die () { local _message="${*} Exiting."; echo "$(_alert emergency)"; safeExit;} +function error () { local _message="${*}"; echo "$(_alert error)"; } +function warning () { local _message="${*}"; echo "$(_alert warning)"; } +function notice () { local _message="${*}"; echo "$(_alert notice)"; } +function info () { local _message="${*}"; echo "$(_alert info)"; } +function debug () { local _message="${*}"; echo "$(_alert debug)"; } +function success () { local _message="${*}"; echo "$(_alert success)"; } +function input() { local _message="${*}"; echo -n "$(_alert input)"; } +function header() { local _message="========== ${*} ========== "; echo "$(_alert header)"; } + +# Log messages when verbose is set to "true" +verbose() { + if [[ "${verbose}" = "true" ]] || [ "${verbose}" == "1" ]; then + debug "$@" + fi +} + + +# SCRIPTNAME +# ------------------------------------------------------ +# Will return the name of the script being run +# ------------------------------------------------------ +scriptName=`basename $0` #Set Script Name variable +scriptBasename="$(basename ${scriptName} .sh)" # Strips '.sh' from scriptName + +# TIMESTAMPS +# ------------------------------------------------------ +# Prints the current date and time in a variety of formats: +# +# ------------------------------------------------------ +now=$(LC_ALL=C date +"%m-%d-%Y %r") # Returns: 06-14-2015 10:34:40 PM +datestamp=$(LC_ALL=C date +%Y-%m-%d) # Returns: 2015-06-14 +hourstamp=$(LC_ALL=C date +%r) # Returns: 10:34:40 PM +timestamp=$(LC_ALL=C date +%Y%m%d_%H%M%S) # Returns: 20150614_223440 +today=$(LC_ALL=C date +"%m-%d-%Y") # Returns: 06-14-2015 +longdate=$(LC_ALL=C date +"%a, %d %b %Y %H:%M:%S %z") # Returns: Sun, 10 Jan 2016 20:47:53 -0500 +gmtdate=$(LC_ALL=C date -u -R | sed 's/\+0000/GMT/') # Returns: Wed, 13 Jan 2016 15:55:29 GMT + +# THISHOST +# ------------------------------------------------------ +# Will print the current hostname of the computer the script +# is being run on. +# ------------------------------------------------------ +thisHost=$(hostname) + +# ------------------------------------------------------ +# These functions are for use with different trap scenarios +# ------------------------------------------------------ + +# Non destructive exit for when script exits naturally. +# Usage: Add this function at the end of every script +function safeExit() { + # Delete temp files, if any + if is_dir "${tmpDir}"; then + rm -r "${tmpDir}" + fi + trap - INT TERM EXIT + exit +} + +# readFile +# ------------------------------------------------------ +# Function to read a line from a file. +# +# Most often used to read the config files saved in my etc directory. +# Outputs each line in a variable named $result +# ------------------------------------------------------ +function readFile() { + unset "${result}" + while read result + do + echo "${result}" + done < "$1" +} + +# Escape a string +# ------------------------------------------------------ +# usage: var=$(escape "String") +# ------------------------------------------------------ +escape() { echo "${@}" | sed 's/[]\.|$(){}?+*^]/\\&/g'; } + +# needSudo +# ------------------------------------------------------ +# If a script needs sudo access, call this function which +# requests sudo access and then keeps it alive. +# ------------------------------------------------------ +function needSudo() { + # Update existing sudo time stamp if set, otherwise do nothing. + sudo -v + while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null & +} + +# convertsecs +# ------------------------------------------------------ +# Convert Seconds to human readable time +# +# To use this, pass a number (seconds) into the function as this: +# print "$(convertsecs $TOTALTIME)" +# +# To compute the time it takes a script to run use tag the start and end times with +# STARTTIME=$(date +"%s") +# ENDTIME=$(date +"%s") +# TOTALTIME=$(($ENDTIME-$STARTTIME)) +# ------------------------------------------------------ +function convertsecs() { + ((h=${1}/3600)) + ((m=(${1}%3600)/60)) + ((s=${1}%60)) + printf "%02d:%02d:%02d\n" $h $m $s +} + + +# Join +# ---------------------------------------------- +# This function joins items together with a user specified separator +# Taken whole cloth from: http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array +# +# Usage: +# join , a "b c" d #a,b c,d +# join / var local tmp #var/local/tmp +# join , "${FOO[@]}" #a,b,c +# ---------------------------------------------- +function join() { local IFS="${1}"; shift; echo "${*}"; } + +# File Checks +# ------------------------------------------------------ +# A series of functions which make checks against the filesystem. For +# use in if/then statements. +# +# Usage: +# if is_file "file"; then +# ... +# fi +# ------------------------------------------------------ + +function is_exists() { + if [[ -e "$1" ]]; then + return 0 + fi + return 1 +} + +function is_not_exists() { + if [[ ! -e "$1" ]]; then + return 0 + fi + return 1 +} + +function is_file() { + if [[ -f "$1" ]]; then + return 0 + fi + return 1 +} + +function is_not_file() { + if [[ ! -f "$1" ]]; then + return 0 + fi + return 1 +} + +function is_dir() { + if [[ -d "$1" ]]; then + return 0 + fi + return 1 +} + +function is_not_dir() { + if [[ ! -d "$1" ]]; then + return 0 + fi + return 1 +} + +function is_symlink() { + if [[ -L "$1" ]]; then + return 0 + fi + return 1 +} + +function is_not_symlink() { + if [[ ! -L "$1" ]]; then + return 0 + fi + return 1 +} + +function is_empty() { + if [[ -z "$1" ]]; then + return 0 + fi + return 1 +} + +function is_not_empty() { + if [[ -n "$1" ]]; then + return 0 + fi + return 1 +} + +# Test whether a command exists +# ------------------------------------------------------ +# Usage: +# if type_exists 'git'; then +# some action +# else +# some other action +# fi +# ------------------------------------------------------ + +function type_exists() { + if [ "$(type -P "$1")" ]; then + return 0 + fi + return 1 +} + +function type_not_exists() { + if [ ! "$(type -P "$1")" ]; then + return 0 + fi + return 1 +} + +# Test which OS the user runs +# $1 = OS to test +# Usage: if is_os 'darwin'; then + +function is_os() { + if [[ "${OSTYPE}" == $1* ]]; then + return 0 + fi + return 1 +} + + +# SEEKING CONFIRMATION +# ------------------------------------------------------ +# Asks questions of a user and then does something with the answer. +# y/n are the only possible answers. +# +# USAGE: +# seek_confirmation "Ask a question" +# if is_confirmed; then +# some action +# else +# some other action +# fi +# +# Credt: https://github.com/kevva/dotfiles +# ------------------------------------------------------ + +# Ask the question +function seek_confirmation() { + # echo "" + input "$@" + if "${force}"; then + notice "Forcing confirmation with '--force' flag set" + else + read -p " (y/n) " -n 1 + echo "" + fi +} + +# Test whether the result of an 'ask' is a confirmation +function is_confirmed() { + if "${force}"; then + return 0 + else + if [[ "${REPLY}" =~ ^[Yy]$ ]]; then + return 0 + fi + return 1 + fi +} + +function is_not_confirmed() { + if "${force}"; then + return 1 + else + if [[ "${REPLY}" =~ ^[Nn]$ ]]; then + return 0 + fi + return 1 + fi +} + +# Skip something +# ------------------------------------------------------ +# Offer the user a chance to skip something. +# Credit: https://github.com/cowboy/dotfiles +# ------------------------------------------------------ +function skip() { + REPLY=noskip + read -t 5 -n 1 -s -p "${bold}To skip, press ${underline}X${reset}${bold} within 5 seconds.${reset}" + if [[ "$REPLY" =~ ^[Xx]$ ]]; then + notice " Skipping!" + return 0 + else + notice " Continuing..." + return 1 + fi +} + +# unmountDrive +# ------------------------------------------------------ +# If an AFP drive is mounted as part of a script, this +# will unmount the volume. This will only work on Macs. +# ------------------------------------------------------ +function unmountDrive() { + if [ -d "$1" ]; then + diskutil unmount "$1" + fi +} + +# help +# ------------------------------------------------------ +# Prints help for a script when invoked from the command +# line. Typically via '-h'. If additional flags or help +# text is available in the script they will be printed +# in the '$usage' variable. +# ------------------------------------------------------ +function help () { + echo "" 1>&2 + input " $@" 1>&2 + if [ -n "${usage}" ]; then # print usage information if available + echo " ${usage}" 1>&2 + fi + echo "" 1>&2 + exit 1 +} + + +function pauseScript() { + # A simple function used to pause a script at any point and + # only continue on user input + seek_confirmation "Ready to continue?" + if is_confirmed; then + info "Continuing" + else + warning "Exiting Script." + safeExit + fi +} + +function in_array() { + # Determine if a value is in an array. + # Usage: if in_array "VALUE" "${ARRAY[@]}"; then ... + local value="$1"; shift + for arrayItem in "$@"; do + [[ "${arrayItem}" == "${value}" ]] && return 0 + done + return 1 +} + +# Text Transformations +# ----------------------------------- +# Transform text using these functions. +# Adapted from https://github.com/jmcantrell/bashful +# ----------------------------------- + +lower() { + # Convert stdin to lowercase. + # usage: text=$(lower <<<"$1") + # echo "MAKETHISLOWERCASE" | lower + tr '[:upper:]' '[:lower:]' +} + +upper() { + # Convert stdin to uppercase. + # usage: text=$(upper <<<"$1") + # echo "MAKETHISUPPERCASE" | upper + tr '[:lower:]' '[:upper:]' +} + +ltrim() { + # Removes all leading whitespace (from the left). + local char=${1:-[:space:]} + sed "s%^[${char//%/\\%}]*%%" +} + +rtrim() { + # Removes all trailing whitespace (from the right). + local char=${1:-[:space:]} + sed "s%[${char//%/\\%}]*$%%" +} + +trim() { + # Removes all leading/trailing whitespace + # Usage examples: + # echo " foo bar baz " | trim #==> "foo bar baz" + ltrim "$1" | rtrim "$1" +} + +squeeze() { + # Removes leading/trailing whitespace and condenses all other consecutive + # whitespace into a single space. + # + # Usage examples: + # echo " foo bar baz " | squeeze #==> "foo bar baz" + + local char=${1:-[[:space:]]} + sed "s%\(${char//%/\\%}\)\+%\1%g" | trim "$char" +} + +squeeze_lines() { + # {{{ + # + # Removes all leading/trailing blank lines and condenses all other + # consecutive blank lines into a single blank line. + # + # }}} + + sed '/^[[:space:]]\+$/s/.*//g' | cat -s | trim_lines +} + +progressBar() { + # progressBar + # ----------------------------------- + # Prints a progress bar within a for/while loop. + # To use this function you must pass the total number of + # times the loop will run to the function. + # + # usage: + # for number in $(seq 0 100); do + # sleep 1 + # progressBar 100 + # done + # ----------------------------------- + if [[ "${quiet}" = "true" ]] || [ "${quiet}" == "1" ]; then + return + fi + + local width + width=30 + bar_char="#" + + # Don't run this function when scripts are running in verbose mode + if ${verbose}; then return; fi + + # Reset the count + if [ -z "${progressBarProgress}" ]; then + progressBarProgress=0 + fi + + # Do nothing if the output is not a terminal + if [ ! -t 1 ]; then + echo "Output is not a terminal" 1>&2 + return + fi + # Hide the cursor + tput civis + trap 'tput cnorm; exit 1' SIGINT + + if [ ! "${progressBarProgress}" -eq $(( $1 - 1 )) ]; then + # Compute the percentage. + perc=$(( progressBarProgress * 100 / $1 )) + # Compute the number of blocks to represent the percentage. + num=$(( progressBarProgress * width / $1 )) + # Create the progress bar string. + bar= + if [ ${num} -gt 0 ]; then + bar=$(printf "%0.s${bar_char}" $(seq 1 ${num})) + fi + # Print the progress bar. + progressBarLine=$(printf "%s [%-${width}s] (%d%%)" "Running Process" "${bar}" "${perc}") + echo -en "${progressBarLine}\r" + progressBarProgress=$(( progressBarProgress + 1 )) + else + # Clear the progress bar when complete + echo -ne "${width}%\033[0K\r" + unset progressBarProgress + fi + + tput cnorm +} + +htmlDecode() { + # Decode HTML characters with sed + # Usage: htmlDecode + echo "${1}" | sed -f "${SOURCEPATH}/htmlDecode.sed" +} + +htmlEncode() { + # Encode HTML characters with sed + # Usage: htmlEncode + echo "${1}" | sed -f "${SOURCEPATH}/htmlEncode.sed" +} + +urlencode() { + # URL encoding/decoding from: https://gist.github.com/cdown/1163649 + # Usage: urlencode + + local length="${#1}" + for (( i = 0; i < length; i++ )); do + local c="${1:i:1}" + case $c in + [a-zA-Z0-9.~_-]) printf "%s" "$c" ;; + *) printf '%%%02X' "'$c" + esac + done +} + +urldecode() { + # Usage: urldecode + + local url_encoded="${1//+/ }" + printf '%b' "${url_encoded//%/\x}" +} + +parse_yaml() { + # Function to parse YAML files and add values to variables. Send it to a temp file and source it + # https://gist.github.com/DinoChiesa/3e3c3866b51290f31243 which is derived from + # https://gist.github.com/epiloque/8cf512c6d64641bde388 + # + # Usage: + # $ parse_yaml sample.yml > /some/tempfile + # + # parse_yaml accepts a prefix argument so that imported settings all have a common prefix + # (which will reduce the risk of name-space collisions). + # + # $ parse_yaml sample.yml "CONF_" + + local prefix=$2 + local s + local w + local fs + s='[[:space:]]*' + w='[a-zA-Z0-9_]*' + fs="$(echo @|tr @ '\034')" + sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \ + -e "s|^\($s\)\($w\)$s[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" | + awk -F"$fs" '{ + indent = length($1)/2; + if (length($2) == 0) { conj[indent]="+";} else {conj[indent]="";} + vname[indent] = $2; + for (i in vname) {if (i > indent) {delete vname[i]}} + if (length($3) > 0) { + vn=""; for (i=0; i> "${csvFile}" + IFS=$saveIFS + +} + +function json2yaml() { + # convert json files to yaml using python and PyYAML + python -c 'import sys, yaml, json; yaml.safe_dump(json.load(sys.stdin), sys.stdout, default_flow_style=False)' < "$1" +} + +function yaml2json() { + # convert yaml files to json using python and PyYAML + python -c 'import sys, yaml, json; json.dump(yaml.load(sys.stdin), sys.stdout, indent=4)' < "$1" +}