44d3727fe67bccca5da529e5678d74eee712ef9c
[BK-2020-03.git] / unitproc / bktemplate.sh
1 #!/bin/bash
2
3 # Date: 2020-05-04T16:50Z
4 # Author: Steven Baltakatei Sandoval
5 # Description: Template for bash scripts.
6 # Note: Use hide-show-block function to aid readability. (ex: https://www.emacswiki.org/emacs/HideShow ).
7
8 #== Variable Initialization ==
9
10 #== Global constants ==
11 SCRIPT_TTL=10 # Limit script life to this in seconds.
12 PATH="/usr/local/bin/:$PATH" # Add user binary executable directory to PATH.
13 PATH="/opt/bktei:$PATH" # Add 'optional' executable directory to PATH.
14 SCRIPT_HOSTNAME=$(hostname) # Save hostname of system running this script.
15 SCRIPT_VERSION="bktemplate.sh 0.0.0" # Define version of script. Used by function 'showVersion'.
16 SCRIPT_TIME_SHORT="$(date +%Y%m%dT%H%M%S%z)" # Save current date & time in ISO-8601 format (YYYYmmddTHHMMSS+zzzz).
17 SCRIPT_DATE_SHORT="$(date +%Y%m%d)" # Save current date in ISO-8601 format.
18
19 #== Function Definitions ==
20 echoerr() {
21 # Usage: echo [ arguments ]
22 # Description: Prints provided arguments to stderr.
23 # Input: unspecified
24 # Output: stderr
25 # Script function dependencies: none
26 # External function dependencies: echo
27 # Last modified: 2020-04-11T21:16Z
28 # Last modified by: Steven Baltakatei Sandoval
29 # License: GPLv3+
30 # Ref./Attrib:
31 # [1]: # Roth, James (2010-06-07). ["How to print text to stderr instead of stdout"](https://stackoverflow.com/a/2990533). Licensed CC BY-SA 4.0.
32
33 echo "$@" 1>&2; # Define stderr echo function. See [1].
34 return 0; # Function finished.
35 } # Define stderr message function.
36 vbm() {
37 # Usage: vbm "DEBUG:verbose message here"
38 # Description: Prints verbose message ("vbm") to stderr if OPTION_VERBOSE is set to "true".
39 # Input:
40 # - OPTION_VERBOSE variable set by processArguments function. (ex: "true", "false")
41 # - "$@" positional arguments fed to this function.
42 # Output: stderr
43 # Script function dependencies: echoerr
44 # External function dependencies: echo
45 # Last modified: 2020-04-11T23:57Z
46 # Last modified by: Steven Baltakatei Sandoval
47 # License: GPLv3+
48 # Ref./Attrib:
49
50 if [ "$OPTION_VERBOSE" == "true" ]; then
51 FUNCTION_TIME=$(date --iso-8601=ns); # Save current time in nano seconds.
52 echoerr "[$FUNCTION_TIME] ""$@"; # Display argument text.
53 fi
54
55 # End function
56 return 0; # Function finished.
57 } # Verbose message display function.
58 showUsage() {
59 # Usage: showUsage
60 # Description: Displays script usage information.
61 # Input: none
62 # Output: stderr
63 # Script function dependencies: echoerr
64 # External dependencies: bash (5.0.3), echo
65 # Last modified: 2020-05-04T16:11Z
66 # Last modified by: Steven Baltakatei Sandoval
67 # License: GPLv3+
68 # Ref./Attrib.:
69
70 echoerr "USAGE:"
71 echoerr " bktemplate.sh [ options ]"
72 echoerr
73 echoerr "OPTIONS:"
74 echoerr " -h, --help"
75 echoerr " Display help information."
76 echoerr
77 echoerr " --version"
78 echoerr " Display script version."
79 echoerr
80 echoerr " -v, --verbose"
81 echoerr " Display debugging info."
82 echoerr
83 echoerr " -o, --output-file [ file ]"
84 echoerr " Specify output file."
85 echoerr
86 echoerr " -i, --input-file [ file ]"
87 echoerr " Specify input file."
88 echoerr
89 echoerr " -o, --output-dir [ directory ]"
90 echoerr " Specify output directory."
91 echoerr
92 echoerr " -i, --input-dir [ directory ]"
93 echoerr " Specify input directory."
94 echoerr
95
96 # End function
97 return 0; # Function finished.
98 } # Display information on how to use this script.
99 showVersion() {
100 # Usage: showVersion
101 # Descriptoin: Displays script version and license information.
102 # Input: unspecified
103 # Output: stderr
104 # Script function dependencies: echoerr
105 # External function dependencies: echo
106 # Last modified: 2020-04-11T23:57Z
107 # Last modified by: Steven Baltakatei Sandoval
108 # License: GPLv3+
109 # Ref./Attrib:
110
111 # Initialize function
112 vbm "DEBUG:showVersion function called."
113
114 # Perform work
115 OUTPUT="$SCRIPT_VERSION"
116
117 # Display results
118 echoerr "$OUTPUT";
119
120 # End function
121 vbm "DEBUG:showVersion function ended."
122 return 0; # Function finished.
123 } # Display script version.
124 processArguments() {
125 # Usage: processArguments "$@"
126 # Description: Processes provided arguments in order to set script option variables useful for
127 # changing how other functions behave. For example, it may:
128 # 1. Activate verbose mode
129 # Input: "$@" (list of arguments provided to the function)
130 # Output: Sets following variables used by other functions:
131 # OPTION_VERBOSE Indicates verbose mode enable status. (ex: "true", "false")
132 # DIROUT1 Path to output directory.
133 # FILEOUT1 Path to output file.
134 # DIRIN1 Path to input directory.
135 # FILEIN1 Path to input file.
136 # OPTION_FILEOUT1_OVERWRITE Indicates whether file FILEOUT1 should be overwritten (ex: "true", "false')
137 # Script function dependencies:
138 # - echoerr Displays messages to stderr.
139 # - vbm Displays messsages to stderr if OPTION_VERBOSE set to "true".
140 # External dependencies: bash (5.0.3), echo
141 # Last modified: 2020-05-04T14:41Z
142 # Last modified by: Steven Baltakatei Sandoval
143 # License: GPLv3+
144 # Ref./Attrib.:
145 # [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
146
147 # Initialize function
148 #vbm "DEBUG:processArguments function called."
149
150 # Perform work
151 while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
152 #1>&2 echo "DEBUG:Starting processArguments while loop." # Debug stderr message. See [1].
153 #1>&2 echo "DEBUG:Provided arguments are:""$@" # Debug stderr message. See [1].
154 case "$1" in
155 -h | --help) showUsage; exit 1;; # Display usage.
156 --version) showVersion; exit 1;; # Show version
157 -v | --verbose) OPTION_VERBOSE="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
158 -i | --input-file) # Define input file path
159 if [ -f "$2" ]; then # If $2 is file that exists, set FILEIN1 to $2, pop $2.
160 FILEIN1="$2";
161 shift;
162 vbm "DEBUG:Input file FILEIN1 set to:""$2";
163 else
164 echoerr "ERROR: Specified input file does not exist:""$2";
165 echoerr "Exiting.";
166 exit 1;
167 fi ;;
168 -I | --input-dir) # Define input directory path
169 if [ -d "$2" ]; then # If $2 is dir that exists, set DIRIN1 to $2, pop $2.
170 DIRIN1="$2";
171 shift;
172 vbm "DEBUG:Input directory DIRIN1 set to:""$2";
173 else # Display error if $2 is not a valid dir.
174 echoerr "ERROR:Specified input directory does not exist:""$2";
175 echoerr "Exiting.";
176 exit 1;
177 fi ;;
178 -o | --output-file) # Define output file path
179 if [ -f "$2" ]; then # If $2 is file that exists, prompt user to continue to overwrite, set FILEOUT1 to $2, pop $2.
180 echoerr "Specified output file $2 already exists. Overwrite? (y/n):"
181 read m; case $m in
182 y | Y | yes) OPTION_FILEOUT1_OVERWRITE="true";;
183 n | N | no) OPTION_FILEOUT1_OVERWRITE="false";;
184 *) echoerr "Invalid selection. Exiting."; exit 1;;
185 esac
186 if [ "$OPTION_FILEOUT1_OVERWRITE" == "true" ]; then
187 FILEOUT1="$2";
188 shift;
189 vbm "DEBUG:Output file FILEOUT1 set to:""$2";
190 else
191 echoerr "ERORR:Exiting in order to not overwrite output file:""$FILEOUT1";
192 exit 1;
193 fi
194 else
195 FILEOUT1="$2";
196 shift;
197 vbm "DEBUG:Output file FILEOUT1 set to:""$2";
198 fi ;;
199 -O | --output-dir) # Define output directory path
200 if [ -d "$2" ]; then # If $2 is dir that exists, set DIROUT1 to $2, pop $2
201 DIROUT1="$2";
202 shift;
203 vbm "DEBUG:Output directory DIROUT1 set to:""$2";
204 else
205 echoerr "ERROR:Specified output directory is not valid:""$2";
206 echoerr "Exiting.";
207 exit 1;
208 fi ;;
209 *) echoerr "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1].
210 esac
211 shift
212 done
213
214 # End function
215 vbm "DEBUG:processArguments function ended."
216 return 0; # Function finished.
217 } # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.).
218 checkExecutables() {
219 # Usage: checkExecutables [ command1 ] [ command2 ] [...] [ commandN ]
220 # Description: Checks that provided commands exist and displays those that do not exist.
221 # Input:
222 # - command names (arguments)
223 # Output: commands that don't exist (stderr)
224 # Script function dependencies:
225 # - echoerr for displaying errors via stderr
226 # - processArguments for setting OPTION_VERBOSE
227 # - vbm for displaying verbose messages if OPTION_VERBOSE is "true"
228 # External dependencies: bash (5.0.3), command
229 # Last modified: 2020-04-11T23:59Z
230 # Last modified by: Steven Baltakatei Sandoval
231 # License: GPLv3+
232 # Ref./Attrib.:
233 # [1]: SiegeX (2010-12-12). ["Difference between return and exit in Bash functions."](https://stackoverflow.com/a/4419971). Licensed CC BY-SA 4.0.
234 # [2]: Darryl Hein (2009-12-23). ["Add a new element to an array without specifying the index in Bash"](https://stackoverflow.com/a/1951523). Licensed CC BY-SA 4.0.
235 # [3]: kojiro (2012-10-03). ["Convert command line arguments into an array in Bash"](https://stackoverflow.com/a/12711853)
236 # [4]: niieani (2016-01-12). ["How to copy an array in Bash?"](https://stackoverflow.com/a/34733375/10850071). Licensed CC BY-SA 4.0.
237
238 # Initialize function
239 vbm "DEBUG:checkExecutables function called."
240 declare -a candidateCommandsNames # Initialize array for storing positional arguments provided to this function.
241 candidateCommandsNames=("$@") # Save positional arguments to variable as string. See [3].
242 vbm "DEBUG:candidateCommandsNames:""$@"
243 vbm "DEBUG:candidateCommandsNames[0]:""${candidateCommandsNames[0]}"
244 vbm "DEBUG:candidateCommandsNames[1]:""${candidateCommandsNames[1]}"
245 vbm "DEBUG:candidateCommandsNames[2]:""${candidateCommandsNames[2]}"
246 declare -a outputInvalidCommandsArray # Initialize arary for storing names of invalid commands.
247 declare -a outputValidCommandsArray # Initialize array for storing names of valid commands.
248
249 # Perform work
250 for candidateCommandName in "${candidateCommandsNames[@]}"; do # Search through all space-delimited text for valid commands.
251 if command -v "$candidateCommandName" 1>/dev/null 2>/dev/null; then # Check if a command is valid or not.
252 outputValidCommandsArray+=("$candidateCommandName") ; # See [2].
253 vbm "DEBUG:Adding $candidateCommandName to outputValidCommandsArray."
254 else
255 outputInvalidCommandsArray+=("$candidateCommandName") ; # See [2].
256 vbm "DEBUG:Adding $candidateCommandName to outputInvalidCommandsArray."
257 fi
258 done
259
260 # Output results
261 if [ ${#outputInvalidCommandsArray[@]} -gt 0 ]; then # if number of elements in outputInvalidCommandsArray greater than 0, then display offending commands and exit 1.
262 echoerr "ERROR: Invalid commands found:""${outputInvalidCommandsArray[@]}"; # display invalid commands as error
263 exit 1; # See [1].
264 elif [ ${#outputInvalidCommandsArray[@]} -eq 0 ]; then # if number of elements in outputInvalidCommandsArray equals zero, then return 0.
265 vbm "DEBUG: Valid commands are:""${outputValidCommandsArray[@]}"; # display valid commands if verbose mode enabled
266 return 0; # See [1].
267 else
268 echoerr "ERROR: Check outputInvalidCommandsArray.";
269 fi
270
271 # End function
272 vbm "DEBUG:checkExecutables function ended."
273 return 0; # Function finished.
274 } # Check that certain executables exist.
275 updateTimeConstants() {
276 # Usage: updateTimeConstants
277 # Description: Updates time-related variables for use by other scripts.
278 # Input: (none)
279 # Output: Sets following variables:
280 # TIME_CURRENT Current time in long ISO-8601 format. (ex: YYYY-mm-ddTHH:MM:SS+ZZZZ)
281 # TIME_CURRENT_SHORT Current time in short ISO-8601 format. (ex: YYYYmmddTHHMMSS+ZZZZ)
282 # DATE_CURRENT Current date in ISO-8601 format. (ex: YYYY-mm-dd)
283 # DATE_CURRENT_SHORT Current date in short ISO-8601 format. (ex: YYYYmmdd)
284 # DATE_TOMORROW Tomorrow's date in ISO-8601 format. (ex: YYYY-mm-dd)
285 # TIME_NEXT_MIDNIGHT Time of tomorrow's midnight in long (ex: YYYY-mm-ddTHH:MM:SS+ZZZZ)
286 # ISO-861 format.
287 # SEC_TIL_MIDNIGHT Seconds until next midnight.
288 # Script function dependencies:
289 # - echoerr for displaying errors via stderr
290 # - processArguments for setting OPTION_VERBOSE
291 # - vbm for displaying verbose messages if OPTION_VERBOSE is "true"
292 # External dependencies: bash (5.0.3), date, echo
293 # Last modified: 2020-04-11T23:59Z
294 # Last modified by: Steven Baltakatei Sandoval
295 # License: GPLv3+
296 # Ref./Attrib.:
297
298 # Initialize function
299 vbm "DEBUG:updateTimeConstants function called."
300
301 # Perform work
302 TIME_CURRENT="$(date --iso-8601=seconds)" ;
303 TIME_CURRENT_SHORT="$(date -d "$TIME_CURRENT" +%Y%m%dT%H%M%S%z)"
304 DATE_CURRENT="$(date -d "$TIME_CURRENT" --iso-8601=date)" ;
305 DATE_CURRENT_SHORT="$(date -d "$TIME_CURRENT" +%Y%m%d)" ;
306 DATE_TOMORROW="$(date -d "$TIME_CURRENT next day" --iso-8601=date)" ;
307 TIME_NEXT_MIDNIGHT="$(date -d "$DATE_TOMORROW" --iso-8601=seconds)" ;
308 SECONDS_UNTIL_NEXT_MIDNIGHT="$(( $(date +%s -d "$TIME_NEXT_MIDNIGHT") - $(date +%s -d "$TIME_CURRENT") ))" ;
309
310 # End function
311 vbm "DEBUG:updateTimeConstants function ended."
312 return 0; # Function finished.
313 } # Update time constants
314
315 #== Main Program Definition ==
316 main() {
317 # Usage: main "$@" # See [1].
318 # Input: unspecified (note: all Global Constants declared at beginning of script assumed to be available)
319 # OPTION_VERBOSE (used by vbm, set by processArguments) (ex: "true", "false")
320 # Output: unspecified
321 # Script function dependencies:
322 # - echoerr for displaying errors via stderr
323 # - vbm for displaying verbose messages if OPTION_VERBOSE is "true"
324 # - processArguments for setting OPTION_VERBOSE
325 # - checkExecutables for checking that specified commands are available
326 # External dependencies: bash (5.0.3), echo
327 # Last modified: 2020-05-04T16:50Z
328 # Last modified by: Steven Baltakatei Sandoval
329 # License: GPLv3+
330 # Ref./Attrib.:
331 # [1]: ErichBSchulz (2011-11-20). [How to correctly pass bash script arguments to functions](https://stackoverflow.com/a/8198970). Licensed CC BY-SA 4.0.
332
333 # Initialize function
334 processArguments "$@" # Process arguments.
335 vbm "DEBUG:main function called."
336 vbm "DEBUG:main function arguments are:""$@"
337 checkExecutables "echo" "date" "cut" "awk" # Confirm that executables necessary to run are available. Exit if any fail.
338
339 # Process inputs
340 if [ -v FILEIN1 ]; then # VERBOSE: Display contents of FILEIN1 if FILEIN1 has been set.
341 vbm "DEBUG:main function detects input file:""$FILEIN1" ;
342 vbm "DEBUG:contents of following file is displayed below:""$FILEIN1" ;
343 if [ "$OPTION_VERBOSE" == "true" ]; then # display FILEIN1 contents via cat if verbose mode specified
344 echoerr "========""$FILEIN1"" START""========" ;
345 cat "$FILEIN1" 1>&2 ;
346 echoerr "========""$FILEIN1"" END""========" ;
347 fi
348 fi
349
350 # Perform work
351 OUTPUT="$OUTPUT""Hello world.\n"
352 if [ -v FILEIN1 ]; then
353 OUTPUT="$OUTPUT""The b2sum hash of $FILEIN1 is: $(b2sum "$FILEIN1" | awk '{print $1}').\n";
354 fi
355 OUTPUT="$OUTPUT""The current time is:""$SCRIPT_TIME_SHORT\n"
356
357 # Output results
358 echo -e "$OUTPUT"
359
360 if [ -v FILEOUT1 ]; then # if FILEOUT1 set, write to this file.
361 vbm "DEBUG:main function detects output file:""$FILEOUT1" ;
362 echo -e "$OUTPUT" > "$FILEOUT1" ;
363 vbm "DEBUG:main funtion wrote OUTPUT to:""$FILEOUT1" ;
364 elif [ -v DIROUT1 ]; then # else if DIROUT1 set, set FILEOUT1 to timestamped filename, combine into PATHOUT1, write output to PATHOUT1.
365 vbm "DEBUG:main function detects output directory:""$DIROUT1" ;
366 FILEOUT1="$SCRIPT_TIME_SHORT"..output
367 PATHOUT1="$DIROUT1"/"$FILEOUT1"
368 echo -e "$OUTPUT" > $PATHOUT1 ;
369 vbm "DEBUG:main function wrote output file to:""$PATHOUT1" ;
370 fi
371
372 # End function
373 vbm "DEBUG:main function ended."
374 return 0; # Function finished.
375 }
376
377 #== Perform work and exit ==
378 main "$@" # Run main function.
379 exit 0;