Home > OS >  How to make below bash script clean and less repetitive?
How to make below bash script clean and less repetitive?

Time:09-08

I'm making birthday tracker for only a few people and was wondering how to combine all if statements into one since date and name are the only different things in every if statement, rest is same format.

date=`date  %b-%d`
echo $date

if [ $date  == "Sep-09" ]; then
    echo "Happy Birthday abc!"
fi

if [ $date  == "Oct-11" ]; then
    echo "Happy Birthday xyz!"
fi
.
.
.

I think I can use positional arguments ($1 for date, $2 for name..) but can't figure out how to use it for multiple dates and names. Or if there's any better way, that would be good to know as well.

CodePudding user response:

Using case:

...
case "$date" in
    "Sep-09") name=abc;;
    "Oct-11") name=xyz;;
       ...
           *) exit;; # if no condition met
esac

echo "Happy Birthday $name!"

CodePudding user response:

You can use map/dictionary data structure here. You can check example here: How to define hash tables in Bash?

CodePudding user response:

You could store your birthdays in a text file and read them with while and read.

read will let you read into one or more variables, and if there's more words than variables it stuffs all remaining words into the last variable, so it's perfect to use here when the person's name could be multiple words:

help read

The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on, with any leftover words assigned to the last NAME. Only the characters found in $IFS are recognized as word delimiters.

I also suggest using the date format %m-%d rather than %b-%d as it means the dates in your file will be in order (e.g. you can run sort birthdays.txt to see everyone in birthday order, which you couldn't do if the month was represented by 3 letters).

birthdays.txt:

09-08 John Smith
10-11 Alice

checkbirthdays.sh:

#!/bin/bash
nowdate="$(date  %m-%d)"
(
  while read checkdate name ; do
    if [ "$nowdate" = "$checkdate" ] ; then
      echo "Happy Birthday $name!"
    fi
  done
) < birthdays.txt

output of ./checkbirthdays.sh on September 8th:

Happy Birthday John Smith!

CodePudding user response:

Assuming you have bash 4.0 or newer and, names don't contain whitespace or glob characters, using an associative array would be appropriate for this task:

#!/bin/bash

declare -A birthday_to_names=(
    ['Sep-09']='abc def'
    ['Oct-11']='xyz'
)

names=${birthday_to_names[$(date  %b-%d)]}
[[ $names ]] && printf 'Happy Birthday %s!\n' $names

Note that this version congratulates all birthday people if there are multiple names associated with the given birthday.

  • Related