From b64bbf81557962c5076f432250f38d6c9c25819d Mon Sep 17 00:00:00 2001
From: Steven Baltakatei Sandoval <baltakatei@gmail.com>
Date: Sat, 30 Apr 2022 02:08:45 +0000
Subject: [PATCH] feat(user/bkots):Add script to run ots recursively

---
 doc/user/bkots..flowchart.odg       | Bin 0 -> 24436 bytes
 unitproc/bktemp-get_parent_dirnames |  36 ++
 unitproc/bktemp-processArgs         |  59 ++-
 user/bkots                          | 658 ++++++++++++++++++++++++++++
 4 files changed, 732 insertions(+), 21 deletions(-)
 create mode 100644 doc/user/bkots..flowchart.odg
 create mode 100644 unitproc/bktemp-get_parent_dirnames
 create mode 100644 user/bkots

diff --git a/doc/user/bkots..flowchart.odg b/doc/user/bkots..flowchart.odg
new file mode 100644
index 0000000000000000000000000000000000000000..ea0787db2800ec01800885143626877afb9d1697
GIT binary patch
literal 24436
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
X{A#F!hyQIi@{8BEDO%L>+t&X8152L7

literal 0
HcmV?d00001

diff --git a/unitproc/bktemp-get_parent_dirnames b/unitproc/bktemp-get_parent_dirnames
new file mode 100644
index 0000000..1a5184f
--- /dev/null
+++ b/unitproc/bktemp-get_parent_dirnames
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# Desc: Provides newline-delimited list of each parent dir
+
+yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
+die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
+try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
+get_parent_dirnames() {
+    # Desc: Provides newline-delimited list of each parent dir of a file or dir
+    # Usage: get_parent_dirnames arg1
+    # Input: arg1  input  path
+    # Output: stdout   newline-delimited list of parent dirs
+    # Version: 0.0.1
+    # Depends: yell(), die(), try()
+    local path
+
+    # Check input
+    if [[ $# -ne 1 ]]; then die "FATAL:Incorrect number of arguments:$#"; fi;
+    if ! { [[ -f $1 ]] || [[ -d $1 ]]; }; then die "FATAL:Not a file or dir:$1"; fi;
+
+    # Process path
+    path="$1";
+    while [[ -f $path ]] || [[ -d $path ]]; do
+        path="$(dirname "$path")";
+        name_base_previous="$name_base";
+        name_base="$(basename "$path")";
+        ## Check for stop condition (dirname returns same result as previous iteration)
+        if [[ $name_base == "$name_base_previous" ]]; then break; fi;
+        echo "$name_base";
+    done;    
+}; # Output parent dirnames to stdout
+
+# Test code
+sleep 1 && get_parent_dirnames /home/baltakatei/Downloads/ & # should work
+sleep 2 && get_parent_dirnames /home/baltakatei/Downloads/ foo & # should fail
+sleep 3 && get_parent_dirnames bar/baz & # should fail
+sleep 4;
diff --git a/unitproc/bktemp-processArgs b/unitproc/bktemp-processArgs
index ca29c35..27679a2 100644
--- a/unitproc/bktemp-processArgs
+++ b/unitproc/bktemp-processArgs
@@ -4,6 +4,7 @@
 #==BEGIN Define script parameters==
 #===BEGIN Define variables===
 :
+declare -ag arrayPosArgs
 #===END Define variables===
 
 #===BEGIN Declare local script functions===
@@ -17,7 +18,7 @@ vbm() {
     # Input: arg1: string
     #        vars: opVerbose
     # Output: stderr
-    # Depends: bash 5.0.3, GNU-coreutils 8.30 (echo, date)
+    # Depends: bash 5.1.16, GNU-coreutils 8.30 (echo, date)
 
     if [ "$opVerbose" = "true" ]; then
 	functionTime="$(date --iso-8601=ns)"; # Save current time in nano seconds.
@@ -30,7 +31,7 @@ vbm() {
 showUsage() {
     # Desc: Display script usage information
     # Usage: showUsage
-    # Version 0.0.1
+    # Version 0.0.2
     # Input: none
     # Output: stdout
     # Depends: GNU-coreutils 8.30 (cat)
@@ -50,18 +51,21 @@ showUsage() {
         -I, --input-dir
                 Define input directory path.
         -o, --output-file
-                Define output file path
+                Define output file path.
         -O, --output-dir
-                Define output directory path
+                Define output directory path.
+        --
+                Indicate end of options.
 
     EXAMPLE:
       bktemp-processArgs -o foo.txt
+      bktemp-processArgs -o foo.txt -- some_file.txt
 EOF
 } # Display information on how to use this script.
 showVersion() {
     # Desc: Displays script version and license information.
     # Usage: showVersion
-    # Version: 0.0.1
+    # Version: 0.0.2
     # Input: scriptVersion   var containing version string
     # Output: stdout
     # Depends: vbm(), yell, GNU-coreutils 8.30
@@ -70,14 +74,14 @@ showVersion() {
     vbm "DEBUG:showVersion function called."
 
     cat <<'EOF'
-bktemp-processArgs 0.0.1
+bktemp-processArgs 1.0.0
 Copyright (C) 2021 Steven Baltakatei Sandoval
 License GPLv3: GNU GPL version 3
 This is free software; you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
 
-    GNU Coreutils 8.30
-    Copyright (C) 2018 Free Software Foundation, Inc.
+    GNU Coreutils 8.32
+    Copyright (C) 2020 Free Software Foundation, Inc.
     License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
     This is free software: you are free to change and redistribute it.
     There is NO WARRANTY, to the extent permitted by law.
@@ -90,7 +94,7 @@ EOF
 processArgs() {
     # Desc: Processes arguments provided to script.
     # Usage: processArgs "$@"
-    # Version: 0.0.1
+    # Version: 1.0.0
     # Input: "$@"          (list of arguments provided to the function)
     # Output: Sets following variables used by other functions:
     #   opVerbose            Indicates verbose mode enable status.  (ex: "true", "false")
@@ -98,15 +102,18 @@ processArgs() {
     #   pathFileOut1         Path to output file.
     #   pathDirIn1           Path to input directory.
     #   pathFileIn1          Path to input file.
-    #   opFileOut1_overwrite Indicates whether file pathFileOut1 should be overwritten (ex: "true", "false')
+    #   opFileOut1_overwrite Indicates whether file pathFileOut1 should be overwritten (ex: "true", "false").
+    #   arrayPosArgs         Array of remaining positional argments
     # Depends:
     #   yell()           Displays messages to stderr.
     #   vbm()            Displays messsages to stderr if opVerbose set to "true".
-    #   showUsage()      Displays usage information about parent script
-    #   showVersion()    Displays version about parent script
-    # External dependencies: bash (5.0.3), echo
+    #   showUsage()      Displays usage information about parent script.
+    #   showVersion()    Displays version about parent script.
+    #   arrayPosArgs     Global array for storing non-option positional arguments (i.e. arguments following the `--` option).
+    # External dependencies: bash (5.1.16), echo
     # Ref./Attrib.:
     #  [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
+    #  [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams
 
     # Initialize function
     vbm "DEBUG:processArgs function called."
@@ -169,8 +176,16 @@ processArgs() {
 		    yell "ERROR:Specified output directory is not valid:""$2";
 		    yell "Exiting.";
 		    exit 1;
-		fi ;; 
-	    *) yell "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1].
+		fi ;;
+            --) # End of all options. See [2].
+                shift;
+                for arg in "$@"; do
+                    vbm "DEBUG:adding to arrayPosArgs:$arg";
+                    arrayPosArgs+=("$arg");
+                done;
+                break;;
+            -*) showUsage; yell "ERROR: Unrecognized option."; exit 1;; # Display usage
+	    *) showUsage; yell "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1].
 	esac
 	shift
     done
@@ -186,12 +201,14 @@ processArgs() {
 #==BEGIN sample code==
 processArgs "$@";
 yell "DEBUG:Provided arguments..:""$*" 
-yell "DEBUG:opVerbose...........:$opVerbose";
-yell "DEBUG:pathDirOut1.........:$pathDirOut1";
-yell "DEBUG:pathFileOut1........:$pathFileOut1";
-yell "DEBUG:pathDirIn1..........:$pathDirIn1";
-yell "DEBUG:pathFileIn1.........:$pathFileIn1";
-yell "DEBUG:opFileOut1_overwrite:$opFileOut1_overwrite";
+yell "DEBUG:opVerbose...........:${opVerbose:-<unset>}";
+yell "DEBUG:pathDirOut1.........:${pathDirOut1:-<unset>}";
+yell "DEBUG:pathFileOut1........:${pathFileOut1:-<unset>}";
+yell "DEBUG:pathDirIn1..........:${pathDirIn1:-<unset>}";
+yell "DEBUG:pathFileIn1.........:${pathFileIn1:-<unset>}";
+yell "DEBUG:opFileOut1_overwrite:${opFileOut1_overwrite:-<unset>}";
+yell "DEBUG:arrayPosArgs........:$(if [[ -v arrayPosArgs ]]; then declare -p arrayPosArgs; else printf "<unset>"; fi )";
+#yell "DEBUG:arrayPosArgs........:${arrayPosArgs[*]}";
 #==END sample code==
 
 # Author: Steven Baltaktei Sandoval
diff --git a/user/bkots b/user/bkots
new file mode 100644
index 0000000..fa9b7da
--- /dev/null
+++ b/user/bkots
@@ -0,0 +1,658 @@
+#!/usr/bin/env bash
+
+# Define variables
+declare -Ag appRollCall # Associative array for storing app status
+declare -Ag fileRollCall # Associative array for storing file status
+declare -Ag dirRollCall # Associative array for storing dir status
+declare -ag arrayPosArgs # Associative array for processArgs() function
+
+# Declare functions
+yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
+die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
+try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
+checkapp() {
+    # Desc: If arg is a command, save result in assoc array 'appRollCall'
+    # Usage: checkapp arg1 arg2 arg3 ...
+    # Version: 0.1.1
+    # Input: global assoc. array 'appRollCall'
+    # Output: adds/updates key(value) to global assoc array 'appRollCall'
+    # Depends: bash 5.0.3
+    local returnState    
+
+    #===Process Args===
+    for arg in "$@"; do
+	if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command
+	    appRollCall[$arg]="true";
+	    if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
+	else
+	    appRollCall[$arg]="false"; returnState="false";
+	fi;
+    done;
+
+    #===Determine function return code===
+    if [ "$returnState" = "true" ]; then
+	return 0;
+    else
+	return 1;
+    fi;
+} # Check that app exists
+checkfile() {
+    # Desc: If arg is a file path, save result in assoc array 'fileRollCall'
+    # Usage: checkfile arg1 arg2 arg3 ...
+    # Version: 0.1.1
+    # Input: global assoc. array 'fileRollCall'
+    # Output: adds/updates key(value) to global assoc array 'fileRollCall';
+    # Output: returns 0 if app found, 1 otherwise
+    # Depends: bash 5.0.3
+    local returnState
+
+    #===Process Args===
+    for arg in "$@"; do
+	if [ -f "$arg" ]; then
+	    fileRollCall["$arg"]="true";
+	    if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
+	else
+	    fileRollCall["$arg"]="false"; returnState="false";
+	fi;
+    done;
+    
+    #===Determine function return code===
+    if [ "$returnState" = "true" ]; then
+	return 0;
+    else
+	return 1;
+    fi;
+} # Check that file exists
+checkdir() {
+    # Desc: If arg is a dir path, save result in assoc array 'dirRollCall'
+    # Usage: checkdir arg1 arg2 arg3 ...
+    # Version 0.1.2
+    # Input: global assoc. array 'dirRollCall'
+    # Output: adds/updates key(value) to global assoc array 'dirRollCall';
+    # Output: returns 0 if all args are dirs; 1 otherwise
+    # Depends: Bash 5.0.3
+    local returnState
+
+    #===Process Args===
+    for arg in "$@"; do
+	if [ -z "$arg" ]; then
+	    dirRollCall["(Unspecified Dirname(s))"]="false"; returnState="false";
+	elif [ -d "$arg" ]; then
+	    dirRollCall["$arg"]="true";
+	    if ! [ "$returnState" = "false" ]; then returnState="true"; fi
+	else
+	    dirRollCall["$arg"]="false"; returnState="false";
+	fi
+    done
+    
+    #===Determine function return code===
+    if [ "$returnState" = "true" ]; then
+	return 0;
+    else
+	return 1;
+    fi
+} # Check that dir exists
+displayMissing() {
+    # Desc: Displays missing apps, files, and dirs
+    # Usage: displayMissing
+    # Version 1.0.0
+    # Input: associative arrays: appRollCall, fileRollCall, dirRollCall
+    # Output: stderr: messages indicating missing apps, file, or dirs
+    # Output: returns exit code 0 if nothing missing; 1 otherwise
+    # Depends: bash 5, checkAppFileDir()
+    local missingApps value appMissing missingFiles fileMissing
+    local missingDirs dirMissing
+
+    #==BEGIN Display errors==
+    #===BEGIN Display Missing Apps===
+    missingApps="Missing apps  :";
+    #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done
+    for key in "${!appRollCall[@]}"; do
+	value="${appRollCall[$key]}";
+	if [ "$value" = "false" ]; then
+	    #echo "DEBUG:Missing apps: $key => $value";
+	    missingApps="$missingApps""$key ";
+	    appMissing="true";
+	fi;
+    done;
+    if [ "$appMissing" = "true" ]; then  # Only indicate if an app is missing.
+	echo "$missingApps" 1>&2;
+    fi;
+    unset value;
+    #===END Display Missing Apps===
+
+    #===BEGIN Display Missing Files===
+    missingFiles="Missing files:";
+    #for key in "${!fileRollCall[@]}"; do echo "DEBUG:$key => ${fileRollCall[$key]}"; done
+    for key in "${!fileRollCall[@]}"; do
+	value="${fileRollCall[$key]}";
+	if [ "$value" = "false" ]; then
+	    #echo "DEBUG:Missing files: $key => $value";
+	    missingFiles="$missingFiles""$key ";
+	    fileMissing="true";
+	fi;
+    done;
+    if [ "$fileMissing" = "true" ]; then  # Only indicate if an app is missing.
+	echo "$missingFiles" 1>&2;
+    fi;
+    unset value;
+    #===END Display Missing Files===
+
+    #===BEGIN Display Missing Directories===
+    missingDirs="Missing dirs:";
+    #for key in "${!dirRollCall[@]}"; do echo "DEBUG:$key => ${dirRollCall[$key]}"; done
+    for key in "${!dirRollCall[@]}"; do
+	value="${dirRollCall[$key]}";
+	if [ "$value" = "false" ]; then
+	    #echo "DEBUG:Missing dirs: $key => $value";
+	    missingDirs="$missingDirs""$key ";
+	    dirMissing="true";
+	fi;
+    done;
+    if [ "$dirMissing" = "true" ]; then  # Only indicate if an dir is missing.
+	echo "$missingDirs" 1>&2;
+    fi;
+    unset value;
+    #===END Display Missing Directories===
+
+    #==END Display errors==
+    #==BEGIN Determine function return code===
+    if [ "$appMissing" == "true" ] || [ "$fileMissing" == "true" ] || [ "$dirMissing" == "true" ]; then
+	return 1;
+    else
+	return 0;
+    fi
+    #==END Determine function return code===
+} # Display missing apps, files, dirs
+vbm() {
+    # Description: Prints verbose message ("vbm") to stderr if opVerbose is set to "true".
+    # Usage: vbm "DEBUG :verbose message here"
+    # Version 0.2.0
+    # Input: arg1: string
+    #        vars: opVerbose
+    # Output: stderr
+    # Depends: bash 5.0.3, GNU-coreutils 8.30 (echo, date)
+
+    if [ "$opVerbose" = "true" ]; then
+	functionTime="$(date --iso-8601=ns)"; # Save current time in nano seconds.
+	echo "[$functionTime]:$0:""$*" 1>&2;  # Display argument text.
+    fi
+
+    # End function
+    return 0; # Function finished.
+} # Displays message if opVerbose true
+showVersion() {
+    # Desc: Displays script version and license information.
+    # Usage: showVersion
+    # Version: 0.0.1
+    # Input: scriptVersion   var containing version string
+    # Output: stdout
+    # Depends: vbm(), yell, GNU-coreutils 8.30
+
+    # Initialize function
+    vbm "DEBUG:showVersion function called."
+
+    cat <<'EOF'
+bkots 0.0.1
+Copyright (C) 2022 Steven Baltakatei Sandoval
+License GPLv3: GNU GPL version 3
+This is free software; you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+
+    GNU Coreutils 8.32
+    Copyright (C) 2020 Free Software Foundation, Inc.
+    License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
+    This is free software: you are free to change and redistribute it.
+    There is NO WARRANTY, to the extent permitted by law.
+EOF
+    
+    # End function
+    vbm "DEBUG:showVersion function ended."
+    return 0; # Function finished.
+} # Display script version.
+showUsage() {
+    # Desc: Display script usage information
+    # Usage: showUsage
+    # Version 0.0.1
+    # Input: none
+    # Output: stdout
+    # Depends: GNU-coreutils 8.30 (cat)
+    cat <<'EOF'
+    USAGE:
+        bkots [ options ] [PATH...]
+
+    POSITIONAL ARGUMENTS:
+        PATH    Path(s) of file(s) or directory(ies)
+
+    OPTIONS:
+        --dry-run
+                Do everything except run 'ots' commands.
+        -h, --help
+                Display help information.
+        --include-dotfiles
+                Include files and directories starting with '.' (not
+                included by default).
+        -r, --recursive
+                Consider files in dirs recursively.
+        --version
+                Display script version.
+        -v, --verbose
+                Display debugging info.
+        --
+                Mark end of options. Interpret remaining arguments as
+                positional arguments.
+
+    DESCRIPTION:
+        Scans files by file paths or directory paths provided by
+        positional arguments to see if Open Timestamps '.ots' file
+        exists. If so, attempt to upgrade and verify the '.ots'
+        file. If no '.ots' file exists, attempt to create one.
+
+        Files with a dotfile parent directory located anywhere in the
+        file path are ignored by default. (e.g. 'HEAD' in
+        '/home/user/diary/.git/logs/HEAD' because of '.git'). Dotfiles
+        themselves are also ignored by default
+        (e.g. '/home/user/.gitconfig').
+
+    EXAMPLES:
+      bkots -v foo.txt
+      bkots foo.txt bar.pdf /home/username/Pictures/
+EOF
+} # Display information on how to use this script.
+processArgs() {
+    # Desc: Processes arguments provided to script.
+    # Usage: processArgs "$@"
+    # Version: 1.0.0
+    # Input: "$@"          (list of arguments provided to the function)
+    # Output: Sets following variables used by other functions:
+    #   opVerbose            Indicates verbose mode enable status.  (ex: "true", "false")
+    #   arrayPosArgs         Array of remaining positional argments
+    # Depends:
+    #   yell()           Displays messages to stderr.
+    #   vbm()            Displays messsages to stderr if opVerbose set to "true".
+    #   showUsage()      Displays usage information about parent script.
+    #   showVersion()    Displays version about parent script.
+    #   arrayPosArgs     Global array for storing non-option positional arguments (i.e. arguments following the `--` option).
+    # External dependencies: bash (5.1.16), echo
+    # Ref./Attrib.:
+    #  [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
+    #  [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams
+
+    # Initialize function
+    vbm "DEBUG:processArgs function called."
+
+    # Perform work
+    while [ ! $# -eq 0 ]; do   # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
+	#yell "DEBUG:Starting processArgs while loop." # Debug stderr message. See [1].
+        #yell "DEBUG:Provided arguments are:""$*"      # Debug stderr message. See [1].
+	case "$1" in
+            --dry-run) # Do not run ots commands
+                option_dry_run="true";
+                vbm "DEBUG:Option enabled:dry run";;
+	    -h | --help) showUsage; exit 1;; # Display usage.
+            --include-dotfiles) # Include dotfiles
+                option_include_dotfiles="true";
+                vbm "DEBUG:Option enabled:include dotfiles";;
+            -r | --recursive) # Specify recursive option
+                option_recursive="true";
+                vbm "DEBUG:option enabled:include files in dirs recursively";;
+	    --version) showVersion; exit 1;; # Show version
+	    -v | --verbose) opVerbose="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
+            --) # End of all options. See [2].
+                shift;
+                for arg in "$@"; do
+                    vbm "DEBUG:adding to arrayPosArgs:$arg";
+                    arrayPosArgs+=("$arg");
+                done;
+                break;;
+            -*) showUsage; yell "ERROR: Unrecognized option."; exit 1;; # Display usage
+            *) # Assume remaining arguments are positional arguments
+                for arg in "$@"; do
+                    vbm "DEBUG:adding to arrayPosArgs:$arg";
+                    arrayPosArgs+=("$arg");
+                done;
+                break;;
+	    #*) showUsage; yell "ERROR: Unrecognized argument."; exit 1;; # Handle unrecognized options. See [1].
+	esac
+	shift
+    done
+
+    # End function
+    vbm "DEBUG:processArgs function ended."
+    return  0; # Function finished.
+}; # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.).
+get_parent_dirnames() {
+    # Desc: Provides newline-delimited list of each parent dir of a file or dir
+    # Usage: get_parent_dirnames arg1
+    # Input: arg1  input  path
+    # Output: stdout   newline-delimited list of parent dirs
+    # Version: 0.0.1
+    # Depends: yell(), die(), try()
+    local path
+
+    # Check input
+    if [[ $# -ne 1 ]]; then die "FATAL:Incorrect number of arguments:$#"; fi;
+    if ! { [[ -f $1 ]] || [[ -d $1 ]]; }; then die "FATAL:Not a file or dir:$1"; fi;
+
+    # Process path
+    path="$1";
+    while [[ -f $path ]] || [[ -d $path ]]; do
+        path="$(dirname "$path")";
+        name_base_previous="$name_base";
+        name_base="$(basename "$path")";
+        ## Check for stop condition (dirname returns same result as previous iteration)
+        if [[ $name_base == "$name_base_previous" ]]; then break; fi;
+        echo "$name_base";
+    done;    
+}; # Output parent dirnames to stdout
+main() {
+    # Desc: Creates `.ots` file:
+    #     - for each file specified in arrayPosArgs array
+    #     - for each file in each dir specified in arrayPosArgs array
+    #   Output file created alongside each file or in output directory specified by pathDirIn1
+    # Usage: main "$@";
+    # Input: arrayPosArgs  array with positional arguments
+    #        pathDirOut1   path for output `.ots` files (if pathDirOut1 is specified and is a path)
+    # Output: file(s) creates `.ots` file alongside specified files
+    # Depends: find (GNU findutils) 4.8.0, GNU Coreutils 8.32 (sort)
+    # Ref/Attrib: [1] How to create an array of unique elements from a string/array in bash https://unix.stackexchange.com/a/167194
+    #             [2] How to find files containing newlines in their names https://stackoverflow.com/a/21727028
+    local -a file_list file_list_pruned;
+    local -a files_to_verify files_to_upgrade files_to_stamp
+    local -a files_to_verify_pruned files_to_upgrade_pruned files_to_stamp_pruned 
+
+    # Process args
+    processArgs "$@";
+    
+    # Check dependencies
+    if ! checkapp ots find; then
+        displayMissing;
+        die "FATAL:Missing dependencies.";
+    fi;
+    
+    # Check arguments    
+    ## Mark if output dir option specified
+    if [[ -v pathDirOut1 ]]; then
+        vbm "DEBUG:output directory specified:pathDirOut1:$pathDirOut1";
+        if [[ -d $pathDirOut1 ]]; then
+            vbm "DEBUG:pathDirOut1:$pathDirOut1";
+            config_output_dir="true";
+        else
+            die "ERROR:Not a dir:$pathDirOut1";
+        fi;
+    fi;
+
+    # Display ots details
+    vbm "$(type ots)"; # show how 'ots' is defined
+        #TODO: add option to define 'ots' as a bash function that
+        #populates the ots option '--bitcoin-node FILE' with a
+        #user-specified FILE.
+    
+    # Populate file_list
+    vbm "DEBUG:begin populate file_list array";
+    for item in "${arrayPosArgs[@]}"; do
+        vbm "DEBUG:adding to file list:item:$item";
+
+        ## Get full canonicalized path (follow symlinks)
+        item="$(readlink -f "$item")";
+        vbm "DEBUG:item full path:item:$item";
+        
+        ## Add to list: files
+        if [[ -f $item ]]; then
+            vbm "DEBUG:is a file:item:$item";
+            file_list+=("$item");
+            vbm "DEBUG:added to file_list:$item";
+        ## Add to list: files in dirs
+        elif [[ -d $item ]]; then
+            vbm "DEBUG:is a dir:item:$item";
+            ### Check for recursive flag
+            if [[ "$option_recursive" == "true" ]]; then
+                vbm "DEBUG:option_recursive:$option_recursive";
+                while read -r line; do
+                    file_list+=("$line");
+                    vbm "DEBUG:added to file_list:$line";
+                done < <(find "$item" -type f);
+            else
+                while read -r line; do
+                    file_list+=("$line");
+                    vbm "DEBUG:added to file_list:$line";
+                done < <(find "$item" -maxdepth 1 -type f);
+            fi;
+        else
+            die "ERROR:Not a file or dir:item:$item";
+        fi;
+    done;
+    if [[ $opVerbose == "true" ]]; then
+        vbm "DEBUG:file_list:";
+        printf "%s\n" "${file_list[@]}";
+    fi;
+
+    # Prune file_list
+    for item in "${file_list[@]}"; do
+        if ! [[ $option_include_dotfiles == "true" ]]; then
+            ## Ignore files located beneath a dotfile directory (e.g. '/home/my_repo/.git/config')
+            unset flag_contains_dotfile_parent;
+            while read -r line; do
+                ### Check line from output of get_parent_dirnames
+                pattern="^\.";
+                if [[ $line =~ $pattern ]]; then
+                    #### line starts with '.'
+                    vbm "DEBUG:Dotfile parent detected. Not including in file_list_pruned:$item";
+                    vbm "DEBUG:Dotfile in path:item:$item";
+                    vbm "DEBUG:Dotfile parent:line:$line";
+                    flag_contains_dotfile_parent="true";
+                    break
+                fi;
+            done < <(get_parent_dirnames "$item");
+            if [[ $flag_contains_dotfile_parent == "true" ]]; then
+                unset flag_contains_dotfile_parent;
+                continue; # skip to next item (i.e. don't add to file_list_pruned)
+            fi;
+
+            ## Ignore dotfiles themselves
+            item_basename="$(basename "$item")";
+            pattern="^\.";
+            if [[ $item_basename =~ $pattern ]]; then
+                vbm "INFO :Skipping dotfile:item:$item";
+                continue; # skip to next item
+            fi;
+        fi;
+
+        ## Ignore files with newlines present in filename. See [2].
+        if [[ $item =~ $'\n' ]]; then
+            yell "INFO :Skipping file name with newline:$item";
+            continue; # skip to next item
+        fi;
+
+        ## Ignore files that end in '~'.
+        if [[ $item =~ ~$ ]]; then
+            yell "INFO :Skipping file ending in tilde:$item";
+            continue; # skip to next item
+        fi;
+        
+        ## Add item to file_list_pruned
+        file_list_pruned+=("$item");
+    done;
+    if [[ $opVerbose == "true" ]]; then
+        vbm "DEBUG:file_list_pruned:";
+        printf "%s\n" "${file_list_pruned[@]}";
+    fi;
+    
+    # Decide what actions to take for items in file_list_pruned
+    for item in "${file_list_pruned[@]}"; do
+        vbm "DEBUG:considering action to take for item:$item";
+        unset path_src path_prf dir_parent dir_source;
+            
+        ## Check file extension
+        if [[ $item =~ .ots$ ]]; then
+            ### item ends in '.ots'. Item is proof file.
+            vbm "DEBUG:item ends in '.ots'. Item is proof file:item:$item";
+            if [[ -f ${item%.ots} ]]; then
+                #### Proof file (item) is adjacent to source file
+                vbm "DEBUG:Proof file (item) is adjacent to source file.";
+                ##### Upgrade and verify proof file against adjacent source file
+                vbm "DEBUG:Marking proof file to be upgraded and verified.";
+                path_src="${item%.ots}";
+                path_prf="$item";
+                files_to_upgrade+=("$(printf "%s" "$path_prf")");
+                files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
+            else
+                #### Proof file (item) is not adjacent to source file
+                vbm "DEBUG:Proof file (item) is not adjacent to source file.";
+                #### Check if source file in parent dir
+                dir_parent="$(dirname "$(dirname "$item")" )";
+                cand_src_filename="$(basename "$item")";
+                cand_src_path="$dir_parent/$cand_src_filename";
+                if [[ -f "$cand_src_path" ]]; then
+                    ##### source file in parent dir
+                    vbm "DEBUG:found source file in parent:cand_src_path:$cand_src_path";
+                    path_src="$cand_src_path";
+                    path_prf="$item";
+                    files_to_upgrade+=("$(printf "%s" "$path_prf")");
+                    files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
+                else
+                    #### Throw non-fatal error
+                    vbm "DEBUG:Source file not found for proof file:item:$item";
+                    yell "ERROR:Item is proof file but source filei not adjacent in parent dir. item:$item";
+                    #### Attempt upgrade only
+                    vbm "DEBUG:Marking proof file to be upgraded.";
+                    path_prf="$item";
+                    files_to_upgrade+=("$(printf "%s" "$path_prf")");
+                fi;
+            fi;
+        else
+            ### item does not end in '.ots'. Item is source file.
+            vbm "DEBUG:item does NOT end in '.ots'. Item is source file.";
+            if [[ -f "$item".ots ]]; then
+                #### Proof file is adjacent to source file (item).
+                vbm "DEBUG:Proof file is adjacent to source file (item).";
+                ##### Upgrade and verify proof file against adjacent source file.
+                vbm "DEBUG:Marking proof file to be upgraded and verified.";
+                path_src="$item";
+                path_prf="$item.ots";                
+                files_to_upgrade+=("$(printf "%s" "$path_prf")");
+                files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
+            else
+                #### Proof file is not adjacent to source file (item).
+                #### Check if proof file is in subdir
+                vbm "DEBUG:checking if proof file for source file (item) is in subdir:item:$item";
+                unset flag_proof_in_subdir;
+                dir_item="$(dirname "$item")";
+                cand_prf_filename="$(basename "$item")".ots;
+                while read -r line; do
+                    line_basename="$(basename "$line")";
+                    if [[ $line_basename == "$cand_prf_filename" ]]; then
+                        flag_proof_in_subdir="true";
+                        path_prf="$line";
+                        vbm "DEBUG:proof found in subdir at:line:$line";
+                        break;
+                    fi;
+                done < <(find "$dir_item" -mindepth 2 -maxdepth 2 -type f)
+                if [[ $flag_proof_in_subdir == "true" ]]; then
+                    ##### Proof file is in subdir
+                    vbm "DEBUG:Proof file detected in subdir relative to source file (item)";
+                    #path_prf="$path_prf"; # set in while loop
+                    path_src="$item";
+                    files_to_upgrade+=("$(printf "%s" "$path_prf")");
+                    files_to_verify+=("$(printf "%s\n%s" "$path_src" "$path_prf")");
+                else
+                    ##### Proof file is not in subdir
+                    vbm "DEBUG:Proof file not detected in subdir relative to source file (item).";
+                    #### Stamp source file
+                    vbm "DEBUG:Marking source file to be stamped.";
+                    path_src="$item";
+                    files_to_stamp+=("$(printf "%s" "$path_src")")
+                fi;
+                unset flag_proof_in_subdir;
+            fi;            
+        fi;
+    done;
+    unset path_src path_prf dir_item dir_parent cand_prf_filename cand_src_filename line_basename cand_src_path
+
+    # Prune action lists.
+    ## Sort and prune file action arrays
+    ### files to upgrade
+    while read -r -d $'\0' line; do
+        vbm "DEBUG:adding to files_to_upgrade_pruned:line:$line";
+        files_to_upgrade_pruned+=("$line");
+    done < <(printf "%s\0" "${files_to_upgrade[@]}" | sort -zu | shuf -z); # See [1]
+    if [[ $opVerbose == "true" ]]; then
+        vbm "DEBUG:files_to_upgrade_pruned:";
+        printf "%s\n" "${files_to_upgrade_pruned[@]}";
+    fi;
+
+    ### files to verify
+    while read -r -d $'\0' line; do
+        vbm "DEBUG:adding to files_to_verify_pruned:line:$line";
+        files_to_verify_pruned+=("$line");
+    done < <(printf "%s\0" "${files_to_verify[@]}" | sort -zu | shuf -z); # See [1]
+    if [[ $opVerbose == "true" ]]; then
+        vbm "DEBUG:files_to_verify_pruned:";
+        printf "%s\n\n" "${files_to_verify_pruned[@]}";
+    fi;
+
+    ### files to stamp
+    while read -r -d $'\0' line; do
+        vbm "DEBUG:adding to files_to_stamp_pruned:line:$line";
+        files_to_stamp_pruned+=("$line");
+    done < <(printf "%s\0" "${files_to_stamp[@]}" | sort -zu | shuf -z); # See [1]
+    if [[ $opVerbose == "true" ]]; then
+        vbm "DEBUG:files_to_stamp_pruned:";
+        printf "%s\n" "${files_to_stamp_pruned[@]}";
+    fi;
+    
+    # Act on files
+    ## Upgrade files
+    for item in "${files_to_upgrade_pruned[@]}"; do
+        path_prf="$(cut -d $'\n' -f1 < <(echo "$item"))";
+        if [[ -z "$path_prf" ]]; then
+            yell "ERROR:blank upgrade item encountered. Skipping:item:$item";
+            continue;
+        fi;
+        vbm "DEBUG:Attempting to upgrade proof file:path_prf:$path_prf";
+        if [[ ! $option_dry_run == "true" ]]; then
+            ots upgrade "$path_prf";
+        else
+            yell "DEBUG:DRY RUN:Not running:\"ots upgrade $path_prf\"";
+        fi;
+        
+    done;
+
+    ## Verify files
+    for item in "${files_to_verify_pruned[@]}"; do
+        path_src="$(cut -d $'\n' -f1 < <(echo "$item"))";
+        path_prf="$(cut -d $'\n' -f2 < <(echo "$item"))";
+        if [[ -z "$path_src" ]] || [[ -z "$path_prf" ]]; then
+            yell "ERROR:blank verify item encountered. Skipping:item:$item";
+            continue;
+        fi;
+        vbm "DEBUG:Attempting to verify source file:path_src:$path_src";
+        vbm "DEBUG:    against proof file:          path_prf:$path_prf";
+        if [[ ! $option_dry_run == "true" ]]; then
+            ots verify -f "$path_src" "$path_prf";
+        else
+            yell "DEBUG:DRY RUN:Not running:\"ots verify -f $path_src $path_prf\"";
+        fi;
+        
+    done;
+    
+    ## Stamp files
+    for item in "${files_to_stamp_pruned[@]}"; do
+        path_src="$(cut -d $'\n' -f1 < <(echo "$item"))";
+        if [[ -z "$path_src" ]]; then
+            yell "ERROR:blank stamp item encountered. Skipping:item:$item";
+            continue;
+        fi;
+        vbm "DEBUG:Attempting to stamp source file:path_src:$path_src";
+        if [[ ! $option_dry_run == "true" ]]; then
+            ots stamp "$item";
+        else
+            yell "DEBUG:DRY RUN:Not running:\"ots stamp $item\"";
+        fi;
+        
+    done;
+
+}; # main program
+
+# Run program
+main "$@";
-- 
2.39.5