...
Note that in the non-0 exit code case, the program may also report error information on standard error (e.g. ls: cannot access not_a_file: No such file or directory
above).
Tip | ||
---|---|---|
| ||
The $? return code variable must be checked immediately after the called program or sub-shell completes, because any further actions in the caller will change $?. One way to do this is to save off the value $? of in another variable (e.g. res=$?). |
...
Code Block | ||
---|---|---|
| ||
#!/bin/bash # Script version global variable. Edit this whenever changes are made. __ADVANCED_BASH_VERSION__="step_03" # ======================================================================= # Helper functions # ======================================================================= # Shorter format date date2() { date '+%Y-%m-%d %H:%M'; } # Echo's its arguments and the date to std error echo_se() { echo "$@ - `date2`" 1>&2; } maybe_echo() { local do_echo=${ECHO_VERBOSE:-1} if [[ "$do_echo" == "1" ]]; then echo_se "$@"; fi } # Sets up auto-logging to a log file in the current directory # using the specified logFileTag (arg 1) in the log file name. auto_log() { local logFileTag="$1" if [[ "$logFileTag" != "" ]]; then local logFilePath="./autoLog_${logFileTag}.log" maybe_echo ".. logging to $logFilePath" exec 1> >(tee "$logFilePath") 2>&1 res=$? if [[ "$res" != "0" ]]; then echo_se "** ERROR: auto logging returned non-0 exit code $res" exit 255 fi else echo_se "** ERROR in auto_log: no logFile argument provided" exit 255 fi } # ======================================================================= # Command processing functions # ======================================================================= # function that says "Hello World!" and displays user-specified text. function helloWorld() { local txt1=$1 local txt2=$2 shift; shift local rest=$@ echo "Hello World!" echo " text 1: '$txt1'" echo " text 2: '$txt2'" echo " rest: '$rest'" } # function that displays its 1st argument on standard output and # its 2nd argument on standard error function stdStreams() { local outTxt=${1:-"text for standard output"} local errTxt=${2:-"text for standard error"} echo "to standard output: '$outTxt'" echo_se "to standard error: '$errTxt'" } # function that illustrates auto-logging and capturing function output # arg 1 - (required) tag to identify the logfile # arg 2 - (optional) text for standard output # arg 3 - (optional) text for standard error function testAutolog() { local logFileTag="$1" local outTxt=${2:-"text for standard output"} local errTxt=${3:-"text for standard error"} auto_log "$logFileTag" echo -e "\n1) Call stdStreams with output and error text:" stdStreams "$outTxt" "$errTxt" echo -e "\n2) Capture echo output in a variable and display it:" local output=`echo $outTxt` echo -e " echo output was:\n$output" echo -e "\n3) Call echo_se with error text:" echo_se "$errTxt" echo -e "\n4)Capture echo_se function output in a variable and display it:" output=`echo_se "$errTxt"` echo -e "echo_se output was: '$output'" } # ======================================================================= # Main script command-line processing # ======================================================================= function usage() { echo " advanced_bash.sh, version $__ADVANCED_BASH_VERSION__ Usage: advanced_bash.sh <command> [arg1 arg2...] Commands: helloWorld [text to display] stdStreams [text for stdout] [text for stderr] testAutolog <logFileTag> [text for stdout] [text for stderr] " exit 255 } CMD=$1 # initially $1 will be the command shift # after "shift", $1 will be the 2nd command-line argument; $2 the 3rd, etc. # and $@ will be arguments 2, 3, etc. # Only show usage if there is a command argument, # making it possible to source this file if [[ "$CMD" != "" ]]; then case "$CMD" in helloWorld) helloWorld "$@" ;; stdStreams) stdStreams "$1" "$2" ;; testAutolog) testAutolog "$1" "$2" "$3" ;; *) usage ;; esac fi |
The Parts
modified command argument processing
To allow our script to be source'd, top-level command argument processing has been modified so that the usage function (which calls exit) is only called if there is a command argument provided.
...
language | bash |
---|
...
date2 and maybe_echo functions
The echo_se function has been modified to call a new date2 function, which calls date specifying a custom, shorter date format.
We've also added a maybe_echo function that calls echo_se if the user wants verbose messages (which is the default, based on the ECHO_VERBOSE environment variable, but that the user can change by export'ing a different value to the script).
Code Block | ||
---|---|---|
| ||
# Shorter format date date2() { date '+%Y-%m-%d %H:%M'; } # Echo's its arguments and the date to std error echo_se() { echo "$@ - `date2`" 1>&2; } maybe_echo() { local do_echo=${ECHO_VERBOSE:-1} if [[ "$do_echo" == "1" ]]; then echo_se case "$CMD$@"; in fi } |
modified command argument processing
To allow our script to be source'd, top-level command argument processing has been modified so that the usage function (which returns a non-0 exit code with exit 255) is only called if there is a command argument provided.
Code Block | ||
---|---|---|
| ||
CMD=$1 helloWorld)# helloWorldinitially "$@"$1 will be the command shift ;; # after stdStreams) stdStreams "$1shift", "$2"$1 will be the 2nd command-line argument;; $2 the 3rd, etc. testAutolog) testAutolog "$1" "$2" "$3" # ;;and $@ will be arguments *) usage ;; esac fi |
So we only see usage if we type something after the script name:
Code Block | ||
---|---|---|
| ||
# Does not show usage
~/workshop/step_03.sh
# Shows usage
~/workshop/step_03.sh x |
date2 and maybe_echo functions
The echo_se function has been modified to call a new date2 function, which calls date specifying a custom, shorter date format.
We've also added a maybe_echo function that calls echo_se if the user wants verbose messages (which is the default, based on the ECHO_VERBOSE environment variable, but that the user can change by export'ing a different value to the script).
Code Block | ||
---|---|---|
| ||
# Shorter format date date2() { date '+%Y-%m-%d %H:%M'; } # Echo's its arguments and the date to std error echo_se() { echo "$@ - `date2`" 1>&2; } maybe_echo() { local do_echo=${ECHO_VERBOSE:-1} if [[ "$do_echo" == "1" ]]; then echo_se "$@"; fi }2, 3, etc. # Only show usage if there is a command argument, # making it possible to source this file if [[ "$CMD" != "" ]]; then case "$CMD" in helloWorld) helloWorld "$@" ;; stdStreams) stdStreams "$1" "$2" ;; testAutolog) testAutolog "$1" "$2" "$3" ;; *) usage ;; esac fi |
So we only see usage if we type something after the script name:
Code Block | ||
---|---|---|
| ||
# Does not show usage
~/workshop/step_03.sh
# Shows usage
~/workshop/step_03.sh x |
testing source'd functions
...