3 # Date: 2020-05-04T18:50Z
4 # Author: Steven Baltakatei Sandoval
5 # Description: Script to lookup file hash from existing hash list.
6 # Note: Use hide-show-block function to aid readability. (ex: https://www.emacswiki.org/emacs/HideShow ).
8 #== Variable Initialization ==
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.
19 #== Function Definitions ==
21 # Usage: echo [ arguments ]
22 # Description: Prints provided arguments to 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
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.
33 echo "$@" 1>&2; # Define stderr echo function. See [1].
34 return 0; # Function finished.
35 } # Define stderr message function.
37 # Usage: vbm "DEBUG:verbose message here"
38 # Description: Prints verbose message ("vbm") to stderr if OPTION_VERBOSE is set to "true".
40 # - OPTION_VERBOSE variable set by processArguments function. (ex: "true", "false")
41 # - "$@" positional arguments fed to this function.
43 # Script function dependencies: echoerr
44 # External function dependencies: echo
45 # Last modified: 2020-04-11T23:57Z
46 # Last modified by: Steven Baltakatei Sandoval
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.
56 return 0; # Function finished.
57 } # Verbose message display function.
60 # Description: Displays script usage information.
63 # Script function dependencies: echoerr
64 # External dependencies: bash (5.0.3), echo
65 # Last modified: 2020-05-04T16:58Z
66 # Last modified by: Steven Baltakatei Sandoval
71 echoerr
" bklu [OPTIONS] [FILE]"
73 echoerr
" [FILE] hash is compared against file contents of directory"
74 echoerr
" specified by --input-dir option or environment variable"
75 echoerr
" BK_FILEHASHLIST_DIR ."
78 echoerr
" --digest-algo [ digest name ]"
79 echoerr
" Specify digest command name. Value should be GNU"
80 echoerr
" coreutils commands such as: sha256sum, md5sum, b2sum."
81 echoerr
" Default value is: b2sum"
84 echoerr
" Display help information."
87 echoerr
" Display script version."
89 echoerr
" -v, --verbose"
90 echoerr
" Display debugging info."
92 echoerr
" -o, --output-file [ file ]"
93 echoerr
" Specify output file."
95 echoerr
" -i, --input-file [ file ]"
96 echoerr
" Specify input file."
98 echoerr
" -o, --output-dir [ directory ]"
99 echoerr
" Specify output directory."
101 echoerr
" -i, --input-dir [ directory ]"
102 echoerr
" Specify input directory."
107 return 0; # Function finished.
108 } # Display information on how to use this script.
111 # Descriptoin: Displays script version and license information.
114 # Script function dependencies: echoerr
115 # External function dependencies: echo
116 # Last modified: 2020-04-11T23:57Z
117 # Last modified by: Steven Baltakatei Sandoval
121 # Initialize function
122 vbm
"DEBUG:showVersion function called."
125 OUTPUT
="$SCRIPT_VERSION"
131 vbm
"DEBUG:showVersion function ended."
132 return 0; # Function finished.
133 } # Display script version.
135 # Usage: processArguments "$@"
136 # Description: Processes provided arguments in order to set script option variables useful for
137 # changing how other functions behave. For example, it may:
138 # 1. Activate verbose mode
139 # Input: "$@" (list of arguments provided to the function)
140 # Output: Sets following variables used by other functions:
141 # OPTION_VERBOSE Indicates verbose mode enable status. (ex: "true", "false")
142 # DIROUT1 Path to output directory.
143 # FILEOUT1 Path to output file.
144 # DIRIN1 Path to input directory.
145 # FILEIN1 Path to input file.
146 # OPTION_FILEOUT1_OVERWRITE Indicates whether file FILEOUT1 should be overwritten (ex: "true", "false')
147 # DIGEST_ALGO Name of digest command (unverified).
148 # Script function dependencies:
149 # - echoerr Displays messages to stderr.
150 # - vbm Displays messsages to stderr if OPTION_VERBOSE set to "true".
151 # External dependencies: bash (5.0.3), echo
152 # Last modified: 2020-05-04T18:13Z
153 # Last modified by: Steven Baltakatei Sandoval
156 # [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
158 # Initialize function
159 #vbm "DEBUG:processArguments function called."
162 while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
163 #1>&2 echo "DEBUG:Starting processArguments while loop." # Debug stderr message. See [1].
164 #1>&2 echo "DEBUG:Provided arguments are:""$@" # Debug stderr message. See [1].
166 -h |
--help) showUsage
; exit 1;; # Display usage.
167 --version) showVersion
; exit 1;; # Show version
168 -v |
--verbose) OPTION_VERBOSE
="true"; vbm
"DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
169 -i |
--input-file) # Define input file path
170 if [ -f "$2" ]; then # If $2 is file that exists, set FILEIN1 to $2, pop $2.
173 vbm
"DEBUG:Input file FILEIN1 set to:""$2";
175 echoerr
"ERROR: Specified input file does not exist:""$2";
179 -I |
--input-dir) # Define input directory path.
180 if [ -d "$2" ]; then # If $2 is dir that exists, set DIRIN1 to $2, pop $2.
183 vbm
"DEBUG:Input directory DIRIN1 set to:""$2";
184 else # Display error if $2 is not a valid dir.
185 echoerr
"ERROR:Specified input directory does not exist:""$2";
189 -o |
--output-file) # Define output file path
190 if [ -f "$2" ]; then # If $2 is file that exists, prompt user to continue to overwrite, set FILEOUT1 to $2, pop $2.
191 echoerr
"Specified output file $2 already exists. Overwrite? (y/n):"
193 y | Y |
yes) OPTION_FILEOUT1_OVERWRITE
="true";;
194 n | N | no
) OPTION_FILEOUT1_OVERWRITE
="false";;
195 *) echoerr
"Invalid selection. Exiting."; exit 1;;
197 if [ "$OPTION_FILEOUT1_OVERWRITE" == "true" ]; then
200 vbm
"DEBUG:Output file FILEOUT1 set to:""$2";
202 echoerr
"ERORR:Exiting in order to not overwrite output file:""$FILEOUT1";
208 vbm
"DEBUG:Output file FILEOUT1 set to:""$2";
210 -O |
--output-dir) # Define output directory path
211 if [ -d "$2" ]; then # If $2 is dir that exists, set DIROUT1 to $2, pop $2
214 vbm
"DEBUG:Output directory DIROUT1 set to:""$2";
216 echoerr
"ERROR:Specified output directory is not valid:""$2";
220 --digest-algo) # Define file digest algorithm command name.
221 if ! [ -z "$2" ]; then # If $2 is non-zero, set DIGEST_ALGO to $2, pop $2
224 vbm
"DEBUG:DIGEST_ALGO set to:""$DIGEST_ALGO";
226 echoerr
"ERROR:Cannot set DIGEST_ALGO because no string specified."; echoerr
"Exiting."; exit 1;
228 *) if [ -f "$1" ] && ! [ -v FILEIN1
]; then # If $1 is file and FILEIN1 not set, then set FILEIN1 to $1, pop $1.
231 vbm
"DEBUG:FILEIN1 set to:""$FILEIN1";
232 else # Handle non-option (ex: [FILE] )
233 echoerr
"ERROR: Unrecognized non-option argument."; echoerr
"Exiting."; exit 1;
240 vbm
"DEBUG:processArguments function ended."
241 return 0; # Function finished.
242 } # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.).
244 # Usage: checkExecutables [ command1 ] [ command2 ] [...] [ commandN ]
245 # Description: Checks that provided commands exist. If one or more do not exist, then display missing commands and exit with error.
247 # - command names (arguments)
248 # Output: commands that don't exist (stderr)
249 # Script function dependencies:
250 # - echoerr for displaying errors via stderr
251 # - processArguments for setting OPTION_VERBOSE
252 # - vbm for displaying verbose messages if OPTION_VERBOSE is "true"
253 # External dependencies: bash (5.0.3), command
254 # Last modified: 2020-05-04T17:12Z
255 # Last modified by: Steven Baltakatei Sandoval
258 # [1]: SiegeX (2010-12-12). ["Difference between return and exit in Bash functions."](https://stackoverflow.com/a/4419971). Licensed CC BY-SA 4.0.
259 # [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.
260 # [3]: kojiro (2012-10-03). ["Convert command line arguments into an array in Bash"](https://stackoverflow.com/a/12711853)
261 # [4]: niieani (2016-01-12). ["How to copy an array in Bash?"](https://stackoverflow.com/a/34733375/10850071). Licensed CC BY-SA 4.0.
263 # Initialize function
264 vbm
"DEBUG:checkExecutables function called."
265 declare -a candidateCommandsNames
# Initialize array for storing positional arguments provided to this function.
266 candidateCommandsNames
=("$@") # Save positional arguments to variable as string. See [3].
267 vbm
"DEBUG:candidateCommandsNames:""$@"
268 vbm
"DEBUG:candidateCommandsNames[0]:""${candidateCommandsNames[0]}"
269 vbm
"DEBUG:candidateCommandsNames[1]:""${candidateCommandsNames[1]}"
270 vbm
"DEBUG:candidateCommandsNames[2]:""${candidateCommandsNames[2]}"
271 declare -a outputInvalidCommandsArray
# Initialize arary for storing names of invalid commands.
272 declare -a outputValidCommandsArray
# Initialize array for storing names of valid commands.
275 for candidateCommandName
in "${candidateCommandsNames[@]}"; do # Search through all space-delimited text for valid commands.
276 if command -v "$candidateCommandName" 1>/dev
/null
2>/dev
/null
; then # Check if a command is valid or not.
277 outputValidCommandsArray
+=("$candidateCommandName") ; # See [2].
278 vbm
"DEBUG:Adding $candidateCommandName to outputValidCommandsArray."
280 outputInvalidCommandsArray
+=("$candidateCommandName") ; # See [2].
281 vbm
"DEBUG:Adding $candidateCommandName to outputInvalidCommandsArray."
286 if [ ${#outputInvalidCommandsArray[@]} -gt 0 ]; then # if number of elements in outputInvalidCommandsArray greater than 0, then display offending commands and exit 1.
287 echoerr
"ERROR: Invalid commands found:""${outputInvalidCommandsArray[@]}"; # display invalid commands as error
289 elif [ ${#outputInvalidCommandsArray[@]} -eq 0 ]; then # if number of elements in outputInvalidCommandsArray equals zero, then return 0.
290 vbm
"DEBUG: Valid commands are:""${outputValidCommandsArray[@]}"; # display valid commands if verbose mode enabled
293 echoerr
"ERROR: Check outputInvalidCommandsArray.";
297 vbm
"DEBUG:checkExecutables function ended."
298 return 0; # Function finished.
299 } # Check that certain executables exist.
300 updateTimeConstants
() {
301 # Usage: updateTimeConstants
302 # Description: Updates time-related variables for use by other scripts.
304 # Output: Sets following variables:
305 # TIME_CURRENT Current time in long ISO-8601 format. (ex: YYYY-mm-ddTHH:MM:SS+ZZZZ)
306 # TIME_CURRENT_SHORT Current time in short ISO-8601 format. (ex: YYYYmmddTHHMMSS+ZZZZ)
307 # DATE_CURRENT Current date in ISO-8601 format. (ex: YYYY-mm-dd)
308 # DATE_CURRENT_SHORT Current date in short ISO-8601 format. (ex: YYYYmmdd)
309 # DATE_TOMORROW Tomorrow's date in ISO-8601 format. (ex: YYYY-mm-dd)
310 # TIME_NEXT_MIDNIGHT Time of tomorrow's midnight in long (ex: YYYY-mm-ddTHH:MM:SS+ZZZZ)
312 # SEC_TIL_MIDNIGHT Seconds until next midnight.
313 # Script function dependencies:
314 # - echoerr for displaying errors via stderr
315 # - processArguments for setting OPTION_VERBOSE
316 # - vbm for displaying verbose messages if OPTION_VERBOSE is "true"
317 # External dependencies: bash (5.0.3), date, echo
318 # Last modified: 2020-04-11T23:59Z
319 # Last modified by: Steven Baltakatei Sandoval
323 # Initialize function
324 vbm
"DEBUG:updateTimeConstants function called."
327 TIME_CURRENT
="$(date --iso-8601=seconds)" ;
328 TIME_CURRENT_SHORT
="$(date -d "$TIME_CURRENT" +%Y%m%dT%H%M%S%z)"
329 DATE_CURRENT
="$(date -d "$TIME_CURRENT" --iso-8601=date)" ;
330 DATE_CURRENT_SHORT
="$(date -d "$TIME_CURRENT" +%Y%m%d)" ;
331 DATE_TOMORROW
="$(date -d "$TIME_CURRENT next day
" --iso-8601=date)" ;
332 TIME_NEXT_MIDNIGHT
="$(date -d "$DATE_TOMORROW" --iso-8601=seconds)" ;
333 SECONDS_UNTIL_NEXT_MIDNIGHT
="$(( $(date +%s -d "$TIME_NEXT_MIDNIGHT") - $(date +%s -d "$TIME_CURRENT") ))" ;
336 vbm
"DEBUG:updateTimeConstants function ended."
337 return 0; # Function finished.
338 } # Update time constants
340 # Usage: getGnucuDigest [algo] [file]
341 # Description: Calculates cryptographic digest using specified GnuCoreutils command.
343 # $1: [algo] (ex: sha256sum, sha512sum, b2sum, md5sum)
346 # Script function dependencies:
347 # - echoerr for displaying errors via stderr
348 # - processArguments for setting OPTION_VERBOSE
349 # - vbm for displaying verbose messages if OPTION_VERBOSE is "true"
350 # - checkExecutables for checking that digest algo commands exist
351 # External dependencies: bash (5.0.3), echo, awk
352 # Last modified: 2020-05-04T18:51Z
353 # Last modified by: Steven Baltakatei Sandoval
356 # [1]: gnu.org (2000-11). [GNU Coreutils](https://www.gnu.org/software/coreutils/manual/coreutils.html). Licensed FDL v1.3+.
357 # [2]: linuxize.com (2019-07-19). [How to Check if a String Contains a Substring in Bash](https://linuxize.com/post/how-to-check-if-string-contains-substring-in-bash/).
359 # Initialize function
360 vbm
"DEBUG:getGnucuDigest function called."
361 DIGEST_ALGO
=$1 # Define candidate digest algorithm
362 TARGET_FILE
=$2 # Define target file to be digested
363 GNUCU_DIGESTS
="b2sum md5sum sha1sum sha224sum sha256sum sha384sum sha512sum" # Define space-delimited string with GNU Coreutils digest algorithms. See [1].
364 vbm
"DEBUG:DIGEST_ALGO set to:""$DIGEST_ALGO"
365 vbm
"TARGET_FILE set to:""$TARGET_FILE"
366 vbm
"GNUCU_DIGESTS set to:""$GNUCU_DIGESTS"
367 checkExecutables
"$DIGEST_ALGO"; # Check that specified alogirthm command available.
368 if [[ "$GNUCU_DIGESTS" =~ .
*"$DIGEST_ALGO".
* ]]; then
369 vbm
"DEBUG:Confirmed to be a valid GNU Coreutils command:""$DIGEST_ALGO";
371 vbm
"ERROR:Not a valid GNU coreutils command:""$DIGEST_ALGO";
373 fi # Check specified algo against GNUCU_DIGESTS. See [2].
376 OUTPUT
="$("$DIGEST_ALGO" "$TARGET_FILE" | awk '{print $1}')"
377 vbm
"DEBUG:Calculated digest using $DIGEST_ALGO is:""$OUTPUT"
383 vbm
"DEBUG:getGnucuDigest function ended."
384 return 0; # Function finished.
385 } # Calculate GNUCoreutils digest
388 #== Main Program Definition ==
390 # Usage: main "$@" # See [1].
391 # Input: unspecified (note: all Global Constants declared at beginning of script assumed to be available)
392 # OPTION_VERBOSE (used by vbm, set by processArguments) (ex: "true", "false")
393 # DIGEST_ALGO (used by getGnucuDigest, set by processArguments) (ex: "md5sum")
394 # Output: unspecified
395 # Script function dependencies:
396 # - echoerr for displaying errors via stderr
397 # - vbm for displaying verbose messages if OPTION_VERBOSE is "true"
398 # - processArguments for setting OPTION_VERBOSE
399 # - checkExecutables for checking that specified commands are available
400 # External dependencies: bash (5.0.3), echo
401 # Last modified: 2020-05-04T18:44Z
402 # Last modified by: Steven Baltakatei Sandoval
405 # [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.
407 # Initialize function
408 processArguments
"$@" # Process arguments.
409 vbm
"DEBUG:main function called."
410 vbm
"DEBUG:main function arguments are:""$@"
411 checkExecutables
"echo" "date" "cut" "awk" "grep" # Confirm that executables necessary to run are available. Exit if any fail.
414 # If DIRIN1 unset and global variable BK_FILEHASHLIST_DIR set and is dir, then set DIRIN1 to BK_FILEHASHLIST_DIR.
415 if ! [ -v DIRN1
] && [ -v BK_FILEHASHLIST_DIR
] && [ -d "$BK_FILEHASHLIST_DIR" ]; then
416 DIRIN1
="$BK_FILEHASHLIST_DIR";
417 vbm
"DEBUG:DIRN1 not set, BK_FILEHASHLIST_DIR is dir, so setting DIRIN1 to BK_FILEHASHLIST_DIR:""$BK_FILEHASHLIST_DIR";
421 if ! [ -v DIGEST_ALGO
]; then # If DIGEST_ALGO is not set then set it to default value of "b2sum"
423 vbm
"DEBUG:DIGEST_ALGO not set. Setting to default value:""$DIGEST_ALGO"
427 # if [ -v FILEIN1 ]; then # VERBOSE: Display contents of FILEIN1 if FILEIN1 has been set.
428 # vbm "DEBUG:main function detects input file:""$FILEIN1" ;
429 # vbm "DEBUG:contents of following file is displayed below:""$FILEIN1" ;
430 # if [ "$OPTION_VERBOSE" == "true" ]; then # display FILEIN1 contents via cat if verbose mode specified
431 # echoerr "========""$FILEIN1"" START""========" ;
432 # cat "$FILEIN1" 1>&2 ;
433 # echoerr "========""$FILEIN1"" END""========" ;
439 DIGEST
="$(getGnucuDigest "$DIGEST_ALGO" "$FILEIN1")" # Calculate digest of FILEIN1
440 vbm
"DEBUG:Hash of $FILEIN1 is:""$DIGEST"
441 vbm
"DEBUG:Value of DIGEST is:""$DIGEST"
442 vbm
"DEBUG:Value of DIRIN1 is:""$DIRIN1"
443 OUTPUT
="$(grep -ri "$DIGEST" "$DIRIN1")" # Search contents of DIRIN1 for pattern DIGEST, save results to OUTPUT.
448 if [ -v FILEOUT1
]; then # if FILEOUT1 set, write to this file.
449 vbm
"DEBUG:main function detects FILEOUT1 set to:""$FILEOUT1" ;
450 echo -e "$OUTPUT" > "$FILEOUT1" ;
451 vbm
"DEBUG:main funtion wrote OUTPUT to:""$FILEOUT1" ;
452 elif [ -v DIROUT1
]; then # else if DIROUT1 set, set FILEOUT1 to timestamped filename, combine into PATHOUT1, write output to PATHOUT1.
453 vbm
"DEBUG:main function detects DIROUT1 set to:""$DIROUT1" ;
454 FILEOUT1
="$SCRIPT_TIME_SHORT"..
"$(basename "$0")".txt
455 PATHOUT1
="$DIROUT1"/"$FILEOUT1"
456 echo -e "$OUTPUT" > $PATHOUT1 ;
457 vbm
"DEBUG:main function wrote output file to:""$PATHOUT1" ;
461 vbm
"DEBUG:main function ended."
462 return 0; # Function finished.
465 #== Perform work and exit ==
466 main
"$@" # Run main function.