Bash script that reads user input and uses “cal” command to validate dates

bashcalscriptingshell-script

I want to write a script that reads my input (for example if my script is called "check", then I would type "check 9 4 1993" and that input would go through the cal command and will check through the calendar whether it is a valid date or not).

My idea below is that if the input that goes through the cal command gives an error it will mean that it's not a valid date, and vice-versa if there's no error than the date is valid. I do realize there's something terribly wrong with this draft (I can't figure out how to make it so that my input will go through the cal command), but I will appreciate some suggestions. Here's the draft anyways:

#!/bin/bash

day=$1; month=$2; year=$3
day=$(echo "$day" | bc)
month=$(echo "$month" | bc)
year=$(echo "$year" | bc)

cal $day $ month $year 2> /dev/null
if [[$? -eq 0 ]]; then
   echo "This is a valid date"
else
   echo "This is an invalid date"
fi

Best Answer

In some Linux distros that I have checked (e,g, Ubuntu 14.04), the packaged cal comes from BSD and not GNU Coreutils. The BSD version does not seem to accept days as a parameter; only months and years. The Ubuntu version does have a -H YYYY-MM-DD option, but that doesn't seem to help.

Instead I would use the date utility. Assuming the GNU Coreutils under Linux I think I would rewrite your script something like:

#!/bin/bash

day=$((10#$1))
month=$((10#$2))
year=$((10#$3))

if date -d $year-$month-$day > /dev/null 2>&1; then
    # cal $month $year
    echo "This is a valid date"
else
    echo "This is an invalid date"
fi

Notes:

  • I am using the shell's own arithmetic expansion to validate input/remove leading zeros, instead of forking a new bc process for each parameter
  • I am using GNU date to parse the input date
  • The date command may be used directly as the if conditional expression. if works by checking process exit codes. Commonly the [ or [[ executables are used instead, but there is no reason other programs can be used if they exit with useful exit codes
  • I'm not sure if you actually wanted the cal output for correct dates or not. If you do, simply uncomment the cal line.
Related Question