We follow the Google style guide for Shell with the following notable exceptions.
We always choose readability, maintainability and simplification over elegance and speed. Always.
To better understand why we make this counterintuitive tradeoff, read this: Yes, Python is Slow, and I Don’t Care
Our goal is business productivity - which is often a different path than absolute code effeciency.
That means we want utilities that are broadly available and accessible to a wide audience for utilization, maintenence and further development.
That also means we will trade spinning up a bigger EC2 instance for the duration of a utility's execution to throw CPU cycles and I/O at a slow-ish utility rather than build inscrutable, ultra-elegant code that few can quickly understand or maintain.
That also means we will adopt whatever style conventions that are required to produce extremely verbose and detailed debug logs and console output to aid development and debugging.
We use bash shell scripts for larger-than-small utilities.
All shell files must include the '.sh' file extension.
Example: aws-services-snapshot.sh
Redirect all output as follows: 2>&1
Example: feed_write_log="$(cat "$write_file_service_names" 2>&1)"
All code must be verbosely commented.
Always prefer to include the comment in the log versus only in the code.
Example:
#
fnWriteLog ${LINENO} ""
fnWriteLog ${LINENO} "loading variable 'count_lines_service_snapshot_recursive' "
count_lines_service_snapshot_recursive="$(echo "$service_snapshot_recursive" | wc -l)"
fnWriteLog ${LINENO} ""
After setting a variable or loading a file, always reflect the variable value or file contents in the log
Example:
#
fnWriteLog ${LINENO} level_0 ""
fnWriteLog ${LINENO} level_0 "value of variable 'service_snapshot':"
fnWriteLog ${LINENO} level_0 "$service_snapshot"
fnWriteLog ${LINENO} level_0 ""
#
fnWriteLog ${LINENO} level_0 ""
fnWriteLog ${LINENO} level_0 "contents of file "$this_utility_acronym"-write-file-services-recursive-load.json:"
feed_write_log="$(cat "$this_path_temp"/"$this_utility_acronym"-write-file-services-recursive-load.json)"
fnWriteLog ${LINENO} level_0 "$feed_write_log"
fnWriteLog ${LINENO} level_0 ""
#
All non-code lines must begin with '#'.
Example:
#
# set the command/pipeline error line number
error_line_pipeline="$((${LINENO}-7))"
#
#
Use 4 spaces -- never tabs -- for indentation.
There is no maximum line length but please avoid long lines wherever possible.
Put 'do' on a new line after 'while'.
Start a new line after 'do' and indent the code in the 'do' section by four spaces.
Example:
while read -r aws_service aws_command aws_query_parameter aws_service_key
do
fnWriteLog ${LINENO} ""
Use a '#' line to seperate 'if' sections from the surrounding code.
Include a comment describing what is being tested.
Do not use a ';' after the '[[ ]]' test. Start a new line.
Put 'then' on a new line indented four spaces.
Put the code to execute on a new line below 'then' indented four spaces.
Put a comment on the same line as the closing 'fi' for each 'if' section (this style has not yet been rigorously applied to the existing code).
Example:
#
fnWriteLog ${LINENO} ""
fnWriteLog ${LINENO} "checking to see if the service name was added to the global list "
if [[ "$count_global_services_names" -lt "$count_global_services_names_check" ]]
then
#
fnWriteLog ${LINENO} ""
fnWriteLog ${LINENO} "resetting the variable 'count_global_services_names_check' "
count_global_services_names_check=0
fnWriteLog ${LINENO} ""
fnWriteLog ${LINENO} "value of variable 'count_global_services_names_check': "$count_global_services_names_check" "
#
fnWriteLog ${LINENO} "skipping to the next service via the 'continue' command "
#
continue
#
fi # end check for global service
#
When calling a function, include a '#' line above and below the function name (this style has not yet been rigorously applied to the existing code).
Example:
#
# display the header
fnHeader
#
fnDeleteWorkFiles
#
All statements read left-to-right.
The only exception is feeding variables and files into 'while' loops.
Exception example:
#
done< <(echo "$driver_global_services")
#
All variable and function names are heirachical left-to-right
Examples:
- this_log_file
- this_log_file_errors
- this_log_file_errors_full_path
- fnStatusBar
- fnStatusBarTask
- fnStatusBarTaskSub
All function names begin with 'fn' and are CamelCase.
Example: fnFunctionNameSample
All function declarations include the 'function' keyword.
Example: function fnFunctionNameSample
No spaces are allowed in filenames.
All filenames are lowercase and dash '-' seperated.
All filenames include an explicit dot '.' seperated file extension.
Example: file-input-sample-name.txt
A "main" function is not required.
The EGL AWS utilities use a 'fnWriteLog' function to control output to the log(s) and the console.
Except when setting a variable, each line of code must begin with: 'fnWriteLog ${LINENO}'.
Example:
fnWriteLog ${LINENO} "calling the recursive command file write function"
When using a command, a line pair that loads the variable 'feed_write_log' must be used.
Example:
feed_write_log="$(echo "$snapshot_source_recursive_command" 2>&1)"
fnWriteLog ${LINENO} "$feed_write_log"
To echo to the console, use 'level_0'.
Example:
# in verbose mode so preserve the work files
fnWriteLog ${LINENO} level_0 ""
fnWriteLog ${LINENO} level_0 "In verbose mode: Preserving work files "
fnWriteLog ${LINENO} level_0 ""
fnWriteLog ${LINENO} level_0 "work files are here: "$this_path" "
fnWriteLog ${LINENO} level_0 ""