Several points here:
# Note the leading ':'
while getopts :ht: OPTION
do
case $OPTION in
h)
echo "Hi"
;;
t)
echo "You entered $OPTARG"
if [[ ${OPTARG:0:1} == '-' ]]; then
echo "Invalid value $OPTARG given to -$OPTION" >&2
exit 1
fi
;;
:) echo "$0: -$OPTARG needs a value" >&2;
exit 2
;;
\?) echo "$0: unknown option -$OPTARG" >&2;
exit 3
;;
esac
done
The leading ':' on the option list allows us to do our own error handling. If an unknown option is supplied then OPTION is set to a ?. Note that in the case statement this has to be escaped (prefixed with a \), otherwise it would match any single character.
If a value is not supplied to an option, then OPTION is set to a :. Unfortunately this does not help if someone does:
./x -t -h
since the -h will be taken as the OPTARG to option -t. Hence the extra test.
Notice that all the error messages go to standard-error (>&2). To halt the execution of the script we use exit followed by a number in the range 0-255. The only number with a specific meaning is zero, which means success. The numbers 1-255 can have any meaning that we choose, but all imply failure.
Using your examples:
./x.sh -t -h
You entered -h
Invalid value -h given to -t
./x.sh -h -t aa
Hi
You entered aa
./x.sh -h -t
Hi
./x.sh: -t needs a value
./x.sh -t tea -c
You entered tea
./x.sh: unknown option -c