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