'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