...
Code Block |
---|
|
#!/bin/bash
# Script version global variable. Edit this whenever changes are made.
__ADVANCED_BASH_VERSION__="step_02"
# =======================================================================
# Helper functions
# =======================================================================
# Echo's its arguments to std error
echo_se() { echo "$@" 1>&2; }
# 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"
echo_se ".. logging to $logFilePath"
exec 1> >(tee "$logFilePath") 2>&1
else
echo_se "** ERROR in autoLog: 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" "$outErr$errTxt"
echo -e "\n2) Capture stdStreamsecho output in a variable and display it:"
local output=`stdStreams`echo "$outTxt" "$outErr"`$outTxt`
echo -e "\tstdStreams echo output was:\n$output"
echo -e "\n3) Call echo_se with someerror text:"
echo_se "Some random text$errTxt"
echo -e "\n4)Capture echo_se function output in a variable and display it:"
output=`echo_se "Some random text$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.
case "$CMD" in
helloWorld) helloWorld "$@"
;;
stdStreams) stdStreams "$1" "$2"
;;
testAutolog) testAutolog "$1" "$2" "$3"
;;
*) usage
;;
esac |
...
Code Block |
---|
|
# 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" "$outErr$errTxt"
echo -e "\n2) Capture stdStreamsecho output in a variable and display it:"
local output=`stdStreams "$outTxt" "$outErr"``echo $outTxt`
echo -e "\tstdStreams echo output was:\n$output"
echo -e "\n3) Call echo_se with someerror text:"
echo_se "Some random text$errTxt"
echo -e "\n4)Capture echo_se function output in a variable and display it:"
output=`echo_se "Some random text$errTxt"`
echo -e "echo_se output was: '$output'"
}
|
...
Expand |
---|
|
Executing: Code Block |
---|
| ~/workshop/step_02.sh testAutoLog |
produces this output: Code Block |
---|
auto-logging to ''
** ** ERROR in autoLog: no logFile argument provided |
No further code is executed after the auto_log helper function detects that no tag string has been provicedprovided, because it calls exit. |
exercise 4
...
Expand |
---|
|
Executing: Code Block |
---|
| ~/workshop/step_02.sh testAutoLog test1 |
produces this output: Code Block |
---|
.. logging to ./autoLog_test1.log
1) Call stdStreams with output and error text:
to standard output: 'text for standard output'
to standard error: 'text for standard error'
2) Capture stdStreamsecho output in a variable and display it:
to standard error: 'text for standard error'
stdStreams echo output was:
to standard output:
'text for standard output'
3) Call echo_se with someerror text:
Sometext for randomstandard texterror
4)Capture echo_se function output in a variable and display it:
Sometext for randomstandard texterror
echo_se output was: '' |
|
Why are both standard error and standard output text strings displayed in segment 1) when stdStreams is called?
Expand |
---|
|
Because stdStreams echo's to both standard error and standard output in the current execution environment, where both are directed to the terminal by auto-logging. |
Why is only standard output displayed in segment does the $output variable contain the outTxt in 2) when stdStreams echo is called with output being captured?
Expand |
---|
|
Because backtick evaluation creates a new execution environment, and only standard output is returned replaces the command in backticks ( `...` ) with the command's standard output. |
Why is the $output variable empty in segment 4) when echo_se "Some random text"se is called with output being captured?
Expand |
---|
|
Because backtick evaluation creates a new execution environment, and only Because only a command's standard output is returned by backtick evaluation, not standard error. |
What log file is produced, what are its contents, and why?
Expand |
---|
|
The log file produced is autoLog_test1.log, written to the current directory in force when step_02.sh was called. Its contents (below) are nearly the same as when ~/workshop/step_02.sh testAutoLog test1 is called, except that the ".. logging to ./autoLog_test1.log " line is not reported, since that was written before automatic logging was started. Code Block |
---|
1) Call stdStreams with output and error text:
to standard output: 'text for standard output'
to standard error: 'text for standard error'
2) Capture stdStreamsecho output in a variable and display it:
to standard error: 'text for standard error'
stdStreams echo output was:
to standard output: 'text for standard output'
3) Call echo_se with someerror text:
Sometext for randomstandard texterror
4)Capture echo_se function output in a variable and display it:
Sometext for randomstandard texterror
echo_se output was: '' |
|
exercise 5
What is displayed in the terminal when you call the testAutoLog command but redirect standard output to /dev/null? What is in the log file, and why?
Expand |
---|
|
Executing: Code Block |
---|
| ~/workshop/step_02.sh testAutoLog test1 1> /dev/null |
produces only this output: Code Block |
---|
.. logging to ./autoLog_test1.log |
because after automatic logging is turned on, both standard output and standard error for the script are redirected to standard output by the "exec 1> >(tee "$logFilePath") 2>&1 " line. The ".. logging to ./autoLog_test1.log " message was written before auto logging was enabled. However the autoLog_test1.log log file contents are the same as before, because your command-line redirection only affected your command-line environment, not the script's execution environment. |