+#!/usr/bin/env bash
+# Desc: Prints days
+# Depends: date (GNU Coreutils 8.32)
+# Version: 0.0.1
+# Ref/Attrib: [1] Template:This date in recent years https://en.wikipedia.org/wiki/Template:This_date_in_recent_years
+# [2] Removing leading zeros before passing a shell variable to another command https://stackoverflow.com/a/11130324
+
+declare -g yearRange; # range of years to consider
+
+yell() { echo "$0: $*" >&2; } #o Yell, Die, Try Three-Fingered Claw technique
+die() { yell "$*"; exit 111; } #o Ref/Attrib: https://stackoverflow.com/a/25515370
+try() { "$@" || die "cannot $*"; } #o
+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.1.16, 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
+showUsage() {
+ # Desc: Display script usage information
+ # Usage: showUsage
+ # Version 0.0.2
+ # Input: none
+ # Output: stdout
+ # Depends: GNU-coreutils 8.30 (cat)
+ cat <<'EOF'
+ USAGE:
+ bk_this-date-in-recent-years.sh [ options ] [str day of month]
+
+ OPTIONS:
+ -h, --help
+ Display help information.
+ --version
+ Display script version.
+ -v, --verbose
+ Display debugging info.
+ -r, --iso-range
+ Specify year range (iso-8601 period), e.g.
+ "2010/2020". By default, most recent 10
+ years are considered.
+ --
+ Indicate end of options.
+
+ EXAMPLE:
+ bk_this_date-in-recent-years.sh "05-11"
+ bk_this_date-in-recent-years.sh -r "1990/2020" "05-11"
+ bk_this_date-in-recent-years.sh -r "1990/2020" -- "05-11"
+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)
+ # yearRange Iso date range to consider (e.g. "1999/2020").
+ # Output: Sets following variables used by other functions:
+ # opVerbose Indicates verbose mode enable status. (ex: "true", "false")
+ # opIsoRange Indicates that an iso-8601 date range is specified. (ex: "true", "false")
+ # yearRange Iso date range to consider (e.g. "1999/2020").
+ # 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
+ -h | --help) showUsage; exit 1;; # Display usage.
+ --version) showVersion; exit 1;; # Show version
+ -v | --verbose) opVerbose="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
+ -r | --iso-range)
+ opIsoRange="true"; vbm "DEBUG:Accepting iso-8601 year range."; # Accept iso-8601 year range.
+ shift;
+ yearRange="$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
+ *) for arg in "$@"; do
+ vbm "DEBUG:adding to arrayPosArgs:$arg";
+ arrayPosArgs+=("$arg");
+ done;
+ break;;
+ 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.).
+validatePosArgs() {
+ # Input: arrayPosArgs array with positional arguments
+ # opVerbose bool indicates to vbm() to display verbose text
+ # opIsoRange bool indicates to use a user-provided year range
+ # yearRange str iso-8601 year range provided by -r, --iso-range option
+
+ # Validate year $range
+ re='^[0-9]+/[0-9]+$'; # Simply check (int)/(int). Don't address Gregorian Calendar here.
+ if [[ $opIsoRange == "true" && ! "$yearRange" =~ $re ]] ; then
+ showUsage;
+ yell "ERROR:Not a valid date range (e.g. 2010/2022):$yearRange";
+ return 1;
+ fi;
+ return 0;
+}; # Validate arguments
+main() {
+ # Input: arrayPosArgs array with positional arguments
+ # opVerbose bool indicates to vbm() to display verbose text
+ # opIsoRange bool indicates to use a user-provided year range
+ # yearRange str iso-8601 year range provided by -r, --iso-range option
+ # Output: stdout: dates with days of the week (newline delimited)
+ # Depends: date (GNU Coreutils 8.32)
+ # Depends: processArgs(), yell(), vbm(), showUsage(), showVersion(), validatePosArgs()
+ local dom yc ymin ymax;
+
+ # Check input
+ processArgs "$@";
+ if ! validatePosArgs; then
+ die "FATAL:Invalid positional arguments:$(declare -p arrayPosArgs)";
+ fi;
+
+ # Define year range
+ if [[ ! $opIsoRange == "true" ]]; then
+ ## Default: Most recent 10 years
+ yc="10"; # count of years to consider
+ ymax="$(date +%Y)"; # highest year to consider
+ ymin="$((ymax - yc))"; # earliest year to consider
+ else
+ ## Provided via -r,--iso-range option
+ ymin="$(echo "$yearRange" | cut -d'/' -f1)";
+ ymin="$((10#$ymin))"; # strip leading zeroes. See [2]
+ ymax="$(echo "$yearRange" | cut -d'/' -f2)"; # See [2]
+ ymax="$((10#$ymax))"; # strip leading zeroes. See [2]
+ yc="$((ymax - ymin + 1))";
+ fi;
+ # yell "DEBUG:ymin:$ymin";
+ # yell "DEBUG:ymax:$ymax";
+ # yell "DEBUG:yc :$yc";
+
+ # Check year range
+ if ! [[ $(( ymax - ymin )) -ge 0 ]]; then die "FATAL:Invalid year range:$yearRange"; fi;
+
+ # Print Output
+ ## Get day of month (first positional argument)
+ dom="${arrayPosArgs[0]}";
+ for (( year = ymin; year <= ymax; year++ )); do
+ dstr="$year-$dom";
+ date +%Y-%m-%d\ %A --date="$dstr";
+ # printf "DEBUG:dom :%s\n" "$dom";
+ # printf "DEBUG:ymax:%s\n" "$ymax";
+ # printf "DEBUG:ymin:%s\n" "$ymin";
+ # printf "DEBUG:year:%s\n" "$year";
+ # printf "DEBUG:dstr:%s\n" "$dstr";
+ done;
+}; # main program
+
+main "$@";
+
+
+
+# Author: Steven Baltakatei Sandoval
+# License: GPLv3+
+
+# Ref/Attrib (depends)
+
+ # date (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.
+
+ # Written by David MacKenzie.