Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # ------------------------------------------------------------------------------
- # -- Output ordinal part of date.
- # ------------------------------------------------------------------------------
- # Output ordinal part of date from current date or input integer - or output formatted date.
- # Day of month:
- # echo $(date +"%d").
- # This script gives you the ordinal indicator:
- # th, st, nd, rd
- # Usage:
- # echo $(date +"%A, %d`dateOrdinal.sh` of %B %Y, %I:%M:%S %p")
- # Tuesday, 15th of September 2015, 09:47:05 PM
- # See this written up here:
- # http://robertmarkbramprogrammer.blogspot.com.au/2015/09/date-time-stamps-in-bash-with-ordinal.html
- # http://pastebin.com/xZ1afqqC
- #
- # Author: Robert Mark Bram
- # Tuesday, 15th of September 2015, 10:04:12 PM
- # - Initial script.
- # Sunday, 1st of November 2015, 01:23:58 PM
- # - Adapted to script created from newScriptWithShebangLine.sh.
- # - Added ability to accept an argument to work with.
- # Tuesday, 3rd of November 2015, 11:53:36 PM
- # - Allowed command to accept date and a format so that it can format
- # a date and not just output ordinal.
- # Wednesday, 4th of November 2015, 12:11:27 AM
- # - Check for invalid date.
- # Saturday, 7th of November 2015, 11:40:47 PM
- # - Brought this into line with my latest bash template.
- # Specifically, helpLess is false by default.
- # Saturday, 7th of November 2015, 11:49:18 PM
- # - Fixed yes instead of true. Do we display help (usage) and exit?
- # Treat as variable so that we can finish processing arguments first.
- # Sunday, 8th of November 2015, 12:00:42 AM
- # - Fixed issue with dateInteger having leading zeroes and failing on modulus.
- # ------------------------------------------------------------------------------
- # -- TODO.
- # ------------------------------------------------------------------------------
- #
- # ------------------------------------------------------------------------------
- # -- Dependencies.
- # ------------------------------------------------------------------------------
- # - Date.
- # ------------------------------------------------------------------------------
- # -- Variables for this script.
- # ------------------------------------------------------------------------------
- # -
- # Common variables.
- # --------------------------------
- # Shortcut for the name of this file - for docs.
- commandName=`echo $0 | sed 's|.*/||'`
- # Verbose output?.
- verbose=false
- # Count of non option parameters.
- countNonOptionParameters=0
- # Do we display help in less on ERROR?
- helpLess=false
- # Default exitCode.
- exitCode=0
- # Do we display help (usage) and exit?
- # Treat as variable so that we can finish processing arguments first.
- helpThenExit=false
- # -
- # Script specific variables.
- # --------------------------------
- # Date integer, defaults to current date.
- dateInteger=
- # Format to use on date.
- dateFormat=
- # Date to format. Defaults to now.
- dateToFormat=$(date)
- # The ordinal value: st, nd, rd or th.
- dateOrdinal=
- # ------------------------------------------------------------------------------
- # -- Common functions for this script.
- # ------------------------------------------------------------------------------
- # === FUNCTION ===============================================================
- # DESCRIPTION: Output message if verbose is on
- # PARAMETERS: message to be printed
- # RETURNS: -
- # ==============================================================================
- function message() {
- if [ "$verbose" = true ] ; then
- echo -e "${1}"
- fi
- }
- # === FUNCTION ===============================================================
- # DESCRIPTION: Output help and usage message
- # PARAMETERS: error message to be printed
- # RETURNS: -
- # Example to call usage with a varable and new line in
- # error message:
- # usage $'blah ['"${variable}"$'] with \nnew line.'
- # ==============================================================================
- function usage() {
- errMessage=
- exitCodeRe='^[0-9]+$'
- if [ "$#" -eq 2 ] ; then
- # Error message.
- errMessage=$'\nERROR:\n*** '"${1}"$' ***\n'
- # Error code (if int)
- if [[ "$2" =~ $exitCodeRe ]] ; then
- exitCode="${2}"
- errMessage=${errMessage}$'Exit code: '"${exitCode}"$' \n'
- # If help without less, exit now.
- if [ "${helpLess}" = false ] ; then
- echo "*** ${1} ***"
- outputAllArgs
- exit ${exitCode}
- fi
- fi
- elif [ "$#" -eq 1 ] ; then
- if [[ "$1" =~ $exitCodeRe ]] ; then
- exitCode="${1}"
- fi
- errMessage=HELP
- else
- errMessage=HELP
- fi
- # Give a value to allArgs if verbose.
- if [ "${verbose}" = true ] ; then
- outputAllArgs silent
- fi
- less -XF << STOP_HELP
- $errMessage
- Output ordinal part of date from current date or input integer - or output formatted date.
- Just output ordinal
- Usage: $commandName [-i dateInteger|-d dateToFormat] [Miscellaneous Arguments]
- Just output the ordinal: st, nd, rd or th for day of month (given as integer or
- part of date string). No args means output ordinal for current date.
- Output entire date from given format.
- Usage: $commandName -f dateFormat [-d dateToFormat]
- Given a date format and a date (defaults to current date if not given), output
- formatted date with %O as ordinal within pattern.
- --- Main args
- no args Use current date and just output ordinal.
- [-i dateInteger]
- Outputs ordinal for given day of month (which must be an integer).
- [-d dateToFormat]
- If not given, current date/time will be used [$(date)]. Without
- "-f dateFormat", output ordinal from day of month in this date. With
- "-f dateFormat", output fully formatted date for this date.
- Here are a few examples of what sorts of date we can accept (whatever
- the *date* command can accept).
- date --date='April 14 2015 09:45 am'
- $(date --date='April 14 2015 09:45 am' | sed "s/^/ /")
- date --date='April 14 2015'
- $(date --date='April 14 2015' | sed "s/^/ /")
- date --date='today'
- $(date --date='today' | sed "s/^/ /")
- date --date='now'
- $(date --date='now' | sed "s/^/ /")
- date --date='14 April 2014 9:45:00 pm'
- $(date --date='14 April 2014 9:45:00 pm' | sed "s/^/ /")
- date --date='next Thursday'
- $(date --date='next Thursday' | sed "s/^/ /")
- -f dateFormat
- Means we will output given date with this format.
- "Date string" as per the date command (see man date) with one
- exepction:
- - use %O (capital O) where you want us to insert the ordinal.
- --- Miscellaneous Arguments
- [-v] Verbose output.
- [-h|-help] Displays this message and exits.
- [-H|] If command exits with error, display help in less.
- Useful if NOT using command in a pipe stream to get better help.
- Default is false.
- --- Exit codes.
- 0 - Success!
- 0 - User asked to display help.
- 9 - Function processSingleLetterArguments returned false.
- 10 - Undefined single letter option supplied to processSingleLetterArguments.
- 11 - Option processSingleLetterArguments required an argument and none was supplied.
- 12 - Arg dateInteger must be an integer.
- 13 - Too many trailing arguments. None are accepted.
- 14 - How many days do you think there are in a monnth? Should be 31 or less btw.
- 15 - Cannot supply both dateInteger and dateFormat.
- 16 - Cannot supply both dateInteger and dateToFormat.
- 17 - Cannot supply dateFormat without also supplying dateToFormat.
- 18 - Invalid dateToFormat supplied.
- --- Examples
- - Output ordinal for current date.
- $commandName
- $($commandName | sed "s/^/ /")
- - Output ordinal for tomorrow.
- $commandName -d "tomorrow"
- $($commandName -d "tomorrow" | sed "s/^/ /")
- - Output ordinal for specific date and time.
- $commandName -d "Tue, Nov 03, 2015 11:46:03 PM"
- $($commandName -d "Tue, Nov 03, 2015 11:46:03 PM" | sed "s/^/ /")
- - Output fully formatted date that includes ordinal for tomorrow.
- $commandName -d "tomorrow" -f "%A, %-d%O of %B %Y, %I:%M:%S %p"
- $($commandName -d "tomorrow" -f "%A, %-d%O of %B %Y, %I:%M:%S %p" | sed "s/^/ /")
- ${allArgs}
- STOP_HELP
- # Exit if given error code.
- if [ -n "${exitCode}" ] ; then
- exit ${exitCode}
- fi
- }
- # === FUNCTION ===============================================================
- # DESCRIPTION: Process all arguments to script. How to handle getopts args
- # and operands at the same time:
- # http://stackoverflow.com/a/21169366/257233
- # PARAMETERS: -
- # RETURNS: -
- # ==============================================================================
- function processArguments() {
- # Process all arguments. Make sure number of args is correct.
- # if [ $# -lt 3 ] ; then
- # usage "** Incorrect number of args specified **" 9999
- # fi
- # Loop to handle all parameters
- non_option_parameters=()
- while true; do
- # Process single letter args.
- while getopts "$OPTIONS" option; do
- if ! processSingleLetterArguments "$option"; then
- usage "Function processSingleLetterArguments returned false." 9
- fi
- done
- if ((OPTIND > $#)); then break; fi
- non_option_parameters+=(${!OPTIND})
- ((countNonOptionParameters++))
- ((OPTIND++))
- done
- # Help?
- if [ "${helpThenExit}" = true ] ; then
- usage 0
- fi
- # ---------------------------------------------------------------------------
- # Post argument processing - logic that must be applied once we know all args.
- # ---------------------------------------------------------------------------
- # Only room for one trailing arg or none.
- if [ "${countNonOptionParameters}" -ge 1 ] ; then
- usage "Too many trailing arguments [$countNonOptionParameters]. None are allowed." 13
- fi
- # Cannot supply both dateInteger and dateFormat.
- if [ -n "${dateFormat}" -a -n "${dateInteger}" ] ; then
- usage "Cannot supply both dateInteger [$dateInteger] and dateFormat [$dateFormat]." 15
- fi
- # Cannot supply both dateInteger and dateToFormat.
- if [ -n "${dateToFormat}" -a -n "${dateInteger}" ] ; then
- usage "Cannot supply both dateInteger [$dateInteger] and dateToFormat [$dateToFormat]." 16
- fi
- if [ -n "${dateFormat}" -a -z "${dateToFormat}" ] ; then
- usage "Cannot supply dateFormat [$dateFormat] without also supplying dateToFormat." 17
- fi
- if [ -n "${dateToFormat}" ] ; then
- date --date="${dateToFormat}" &>/dev/null
- if [ "$?" -ne 0 ] ; then
- usage "Invalid dateToFormat [$dateToFormat] supplied." 18
- fi
- fi
- }
- # === FUNCTION ===============================================================
- # DESCRIPTION: Process single letter args via getopts
- # PARAMETERS: -
- # RETURNS: -
- # ==============================================================================
- OPTIONS=":d:f:hHi:v"
- function processSingleLetterArguments() {
- case "$1" in
- # Deal with these ones first, always.
- H ) helpLess=true;;
- v ) verbose=true;;
- h ) helpThenExit=true;;
- # Deal with the rest.
- d ) dateToFormat="$OPTARG";;
- i ) dateInteger="$OPTARG";;
- f ) dateFormat="$OPTARG";;
- \?) usage "Invalid option: -$OPTARG" 10;;
- :) usage "Option -$OPTARG requires an argument." 11;;
- esac
- }
- # === FUNCTION ===============================================================
- # DESCRIPTION: Output all the arguments we have if verbose is turned on.
- # Sets variable allArgs.
- # PARAMETERS: $1 if "silent", DOES NOT output, just sets variable allArgs.
- # RETURNS: -
- # ==============================================================================
- function outputAllArgs() {
- if [ "$verbose" = true ] ; then
- read -r -d '' allArgs << EOM
- --- List of args -----------------------------------------
- Arg commandName: [${commandName}]
- Arg countNonOptionParameters: [${countNonOptionParameters}]
- Arg dateFormat: [${dateFormat}]
- Arg dateInteger: [${dateInteger}]
- Arg dateToFormat: [${dateToFormat}]
- Arg helpLess: [${helpLess}]
- Arg verbose: [${verbose}]
- ----------------------------------------------------------
- EOM
- if [ "${1}" != "silent" ] ; then
- echo "${allArgs}"
- fi
- fi
- }
- # === FUNCTION ===============================================================
- # DESCRIPTION: Get the ordinal from a number.
- # - analyses dateInteger - the day of month.
- # PARAMETERS: -
- # RETURNS: sets dateOrdinal to st, nd, rd or th.
- # ==============================================================================
- function computeOrdinal() {
- # Remove leading zeroes.
- if [ -n "${dateInteger}" ] ; then
- dateInteger=$(echo "${dateInteger}" | sed 's/^0*//')
- fi
- if [ $dateInteger -ge 11 -a $dateInteger -le 13 ] ; then
- dateOrdinal="th"
- else
- case $(( $dateInteger%10 )) in
- 1)
- dateOrdinal=st
- ;;
- 2)
- dateOrdinal=nd
- ;;
- 3)
- dateOrdinal=rd
- ;;
- *)
- dateOrdinal=th
- ;;
- esac
- fi
- }
- # ------------------------------------------------------------------------------
- # -- Script Logic.
- # ------------------------------------------------------------------------------
- # Process all the arguments.
- processArguments "$@"
- outputAllArgs
- # If no date format, just compute ordinal.
- if [ -z "${dateFormat}" ] ; then
- # If dateInteger not given, get it from date.
- if [ -z "${dateInteger}" ] ; then
- dateInteger=$(date --date="${dateToFormat}" +"%d")
- # Otherwise, it must be an integer.
- else
- dateInteger=$(echo $dateInteger | xargs)
- if ! [[ $dateInteger =~ ^[0-9]+$ ]] ; then
- usage "Arg dateInteger [$dateInteger] must be an integer." 12
- fi
- # How many days do you think there are in a month??
- if [ "${dateInteger}" -ge 32 ] ; then
- usage "How many days do you think there are in a monnth? Certainly not [$dateInteger]. Should be 31 or less btw." 14
- fi
- fi
- computeOrdinal
- echo "${dateOrdinal}"
- # Output whole formatted date.
- else
- formattedDate=$(date --date="${dateToFormat}" +"${dateFormat}")
- dateInteger=$(date --date="${dateToFormat}" +"%d")
- computeOrdinal
- formattedDate=$(echo "${formattedDate}" | sed -e "s|[%]O|${dateOrdinal}|g")
- echo "${formattedDate}"
- fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement