Shell Function to Execute a Command and Return the Output

'Shell', whatever that means is one or other species of a collection of ancient language families complicated by an indefinite permutation of complementary, supplementary, and conflictiary forward, backward, and sideward compatibility relations. Lately shell usually means bash, although I know there will be disputes even here. The primary argument for this convention is that all major distros are setup with bash as the default shell. Being an ancient language, its quirks and compatibility knots are more intrusive than what one would desire coming from experience with modern languages, so any idiom that is well completed, clear, and expressive feels like an achievement worth recording.

Here is a function that I created but, after code review, discovered I did not need, but also want to remember. It executes its first argument and 'returns' its output into its second argument. Whether this is actually 'POSIX compliant' I do not know, but that it works on GNU Bash 4.1+ seems to be careful enough to certify my uncertainty constraints.

function EXECUTE()
{
    # $1: Command to execute
    # $2: Capture the output

    if [ -n "${MY_SCRIPT_TEST}" ] ; then
        LOG "${FMT_BLUE}" '' "Would have executed: ${1}"
    else
        LOG "${FMT_MAGENTA}" '' "Executing: ${1}"
        # Set arg 2 to the output resulting from the execution of arg 1
        eval "$2='$(eval ${1})'"
    fi
}

Here's the function in the context of some other useful functions that altogether does something that could be useful and well-defined.

function USAGE()
{
    printf -- '%s\n' "This is my script that performs some actions"
    printf -- '%s\n' "set MY_SCRIPT_COLORS=1 to get colorized output and"
    printf -- '%s\n' "set MY_SCRIPT_TEST=1 to pretend"
}


function SETUP_LOG()
{
    local LOG_DIR=${1}

    VALIDATE_DIR "${LOG_DIR}" 'logging directory'

    # Global variables ########################################################
    PRINTF_HAS_FMT_B=''
    ###########################################################################
    printf '%b%s' 'str' &> /dev/null
    [ "$?" = "0" ] && PRINTF_HAS_FMT_B='yes'
}


function LOG()
{
    local MESSAGE_COLOR=$1
    local PROCESS_ESCAPES=$2
    local MESSAGE=$3
    local TIME_STAMP=$(date +'%Y-%m-%dT%H:%M:%S')

    # Process escape sequences in message if requested and available
    if [ -n "${PROCESS_ESCAPES}" ] ; then
        if [ -n "${PRINTF_HAS_FMT_B}" ] ; then
            MESSAGE=$(printf '%b%s' "${MESSAGE}")
        fi
    fi

    # Log to stdout
    if [ -n "${MY_SCRIPT_COLORS}" ] ; then
        printf -- '\e[00;%sm%s\e[0m\n' "${MESSAGE_COLOR}" "${MESSAGE}"
    else
        printf -- '%s\n' "${MESSAGE}"
    fi

    # Log to log file
    if [ -f "${LOG_FILE}" ] ; then
        printf -- '[%s] %s\n' "${TIME_STAMP}" "${MESSAGE}" >> "${LOG_FILE}"
    fi
}


function VALIDATE_DIR()
{
    local DIR=$1
    local DESC=$2

    if [ -z "${DIR}" ] ; then
        LOG "${FMT_RED}" '' "Please provide the ${DESC}"
        exit 1
    fi

    mkdir -p "${DIR}"
    if [ ! -d "${DIR}" ] ; then
        LOG "${FMT_RED}" '' "Cannot ensure directory ${DIR}"
        exit 1
    fi
}


function VALIDATE_ARGS()
{
    # Global variables ########################################################
    FMT_BLACK=30
    FMT_RED=31
    FMT_GREEN=32
    FMT_YELLOW=33
    FMT_BLUE=34
    FMT_MAGENTA=35
    FMT_CYAN=36
    FMT_WHITE=37
    FMT_EXTENDED=38
    FMT_DEFAULT=39

    LOG_DIR='/tmp/my_script'
    LOG_FILE="${LOG_DIR}/my_script.log"
    ###########################################################################

    # Display help message
    local HELP=''
    case "${1}" in
        '-h') HELP='yes' ;;
        '--help') HELP='yes' ;;
        'help') HELP='yes' ;;
        *) ;;
    esac
    if [ -n "${HELP}" ] ; then
        USAGE
        exit 0
    fi

    SETUP_LOG "${LOG_DIR}"
    LOG "${FMT_CYAN}" '' "Executing command line: ${0} ${*}"
}


function EXECUTE()
{
    # $1: Command to execute
    # $2: Capture the output

    if [ -n "${MY_SCRIPT_TEST}" ] ; then
        LOG "${FMT_BLUE}" '' "Would have executed: ${1}"
    else
        LOG "${FMT_MAGENTA}" '' "Executing: ${1}"
        # Set arg 2 to the output resulting from the execution of arg 1
        eval "$2='$(eval ${1})'"
    fi
}


function PERFORM_SOME_ACTIONS()
{
    local TMP_FILE_COUNT=''
    EXECUTE 'find /tmp -type f | wc -l' TMP_FILE_COUNT
    LOG "Temporary file count is ${TMP_FILE_COUNT}"
}


VALIDATE_ARGS $@
PERFORM_SOME_ACTIONS
Posted: | Source