Robert Mark Bram
Robert Mark Bram

Reputation: 9735

Day of month not an integer

I am making an adjustment a bash script of mine to output the ordinal part (st, nd, rd, th) of a day of month. I am trying to adjust it to be used within a date pattern in the date command.

Here is a simple test to determine if day of month from date command is an int:

dayOfMonth=$(date +"%d") && [[ ${dayOfMonth} =~ ^[0-9]+$ ]] && echo ${dayOfMonth} is an int || echo ${dayOfMonth} is NOT an int

Output is as I expect

01 is an int

Now I put that code into a script:

#!/bin/bash
[[ ${1} =~ ^[0-9]+$ ]] && echo ${1} is an int || echo ${1} is NOT an int

Seems OK:

dateTest.sh 12
12 is an int

But when I try to use it within a date command, the script is giving me conflicting output. echo sees 12 but the test is seeing %2

date --date='06/12/2012 07:21:22' +"`dateTest.sh %d`"
12 is NOT an int

To clarify my purpose, the end result of the script will be something like this:

#!/bin/bash
n=$(date +"%d")

if [ $# -ge 1 ] ; then
   n=$1
   if ! [[ $n =~ ^[0-9]+$ ]] ; then
      echo Arg dateInteger [$dateInteger] must be an integer.
      exit 1
   fi
fi

if [ $n -ge 11 -a $n -le 13 ] ; then
  echo "th"
else
 case $(( $n%10 )) in
 1)
   echo st
   ;;
 2)
   echo nd
   ;;
 3)
   echo rd
   ;;
 *)
   echo th
   ;;
 esac
fi

So that I can it like this:

date --date='06/12/2012 07:21:22' +"%A, %d`dateTest.sh %d` of %B %Y, %I:%M:%S %p"

which would output

Tuesday, 12th of June 2012, 07:21:22 AM

Finished script re-write. Thanks to input from @GordonDavisson, I completed my script re-write: http://pastebin.com/xZ1afqqC. Now it either outputs just the ordinal from an integer, or will output a fully formatted date where you can use standard format strings from date with the addition of "%O" for the ordinal.

Upvotes: 0

Views: 368

Answers (1)

Gordon Davisson
Gordon Davisson

Reputation: 126013

You're doing things in the wrong order -- you have to turn "%d" into an integer (the day of the month) before passing it to your script, not after. Consider the command:

date --date='06/12/2012 07:21:22' +"`dateTest.sh %d`"

What this does is run dateTest.sh %d, i.e. it passes "%d" as the argument to your script. The script naturally outputs "%d is not an int". This is then used as the format string for the date command, i.e. date --date='06/12/2012 07:21:22' +"%d is not an int". The date command replaces the "%d" part with the day number, and leaves the rest alone, giving "12 is not an int".

In order to make this work, you have to get the day number first, then pass that to your script. Something like this:

dateTest.sh "$(date --date='06/12/2012 07:21:22' +"%d")"

Unfortunately, your end result script also wants a bunch of other date formatting done that can't be passed to the dateTest script. I think in that case it'd be best to do it in stages:

dayWithSuffix="$(dateTest.sh "$(date --date='06/12/2012 07:21:22' +"%d")")"
date --date='06/12/2012 07:21:22' +"%A, $dayWithSuffix of %B %Y, %I:%M:%S %p"

BTW, several general scripting suggestions:

  • Send error/debug output to stderr, not stdout, so it doesn't get confused with the script's regular output (part of the problem here). For example, echo "${1} is NOT an int" >&2

  • Speaking of which, put strings that contain variables in double-quotes (as I did in that last example) to avoid weird misparsing of whitespace, wildcards, etc. Your result script, for example, contains echo Arg dateInteger [$dateInteger] must be an integer. -- you probably don't realize that under certain circumstances the [$dateInteger] part will be replaced by a list of filenames.

  • Finally, use $( ... ) instead of backquotes. In most cases they're equivalent, but the parenthesis version is easier to read and avoids some weird parsing oddities of the contents. Notice how I nested two such expressions in the assignment to dayWithSuffix? That's much trickier to get right with backquotes.

Upvotes: 3

Related Questions