2
\$\begingroup\$

This is an updated version of the script Fahrenheit / Celsius temperature converter. I have changed the script to be non-interactive, using positional parameters instead of asking for user input once the script is running. In my testing of the script, everything seems to work as it should. But I am quite new to using positional parameters and I'm wondering if this is the best way of using them or if there might be a more streamlined approach.

help shift says:

shift: shift [n]
    Shift positional parameters.

    Rename the positional parameters $N+1,$N+2 ... to $1,$2 ...  If N is
    not given, it is assumed to be 1.

    Exit Status:
    Returns success unless N is negative or greater than $#.

Which leaves me still uncertain as to what that means exactly or how to implement it correctly. The script seems to work but I'd like to know if I could / should do anything differently.

#!/bin/bash

usage() {
    echo -e "usage: temp [-f][-c]|[number]|[-h]\nExample:\n\ttemp -f 54\n\ttemp -c 24.5\n"
}
re='^-?[0-9]+([.][0-9]+)?$'
if [ "$1" = "" ]; then
    usage
    exit 1
elif [[ ! "$2" =~ $re ]]; then
    usage
    exit 1
elif [[ "$3" != "" ]]; then
    usage
    exit 1
fi
while [ "$1" != "" ]; do
    case $1 in
        -f )    shift
                RES="$(echo "scale=2; (${1}-32)*5/9" | bc -q -l; printf "\b˚C")"
                echo "${1}˚F = "${RES}
                exit
                ;;

        -c )    shift
                RES="$(echo "scale=2; ${1}*9/5+32" | bc -q -l; printf "\b˚F")" 
                echo "${1}˚C = "${RES}
                exit
                ;;

        -h )    usage
                exit
                ;;

        * )     usage
                exit 1
    esac
done
\$\endgroup\$
2
\$\begingroup\$

shift shifts the command line argument list by n, or by 1 if n is unspecified. For example, given -c 25, the value of $1 is -c. After you call shift without parameters, it shifts the parameters by 1, so $1 becomes 25. You used it correctly.

Use here-documents

This is hard to read:

echo -e "usage: temp [-f][-c]|[number]|[-h]\nExample:\n\ttemp -f 54\n\ttemp -c 24.5\n"

Using a here-document, it becomes much easier to read:

usage() {
    cat << EOF
usage: temp [-f][-c]|[number]|[-h]
Example:
    temp -f 54
    temp -c 24.5
EOF
}

Simplify conditions

This can be written slightly simpler:

if [ "$1" = "" ]; then

Like this:

if [ ! "$1" ]; then

This can be written much simpler:

elif [[ "$3" != "" ]]; then
    usage
    exit 1
fi
while [ "$1" != "" ]; do

Like this:

elif [[ "$3" ]]; then
    usage
    exit 1
fi
while [ "$1" ]; do

Simplify the bc calls

These statements are unnecessarily complicated:

-f )    shift
        RES="$(echo "scale=2; (${1}-32)*5/9" | bc -q -l; printf "\b˚C")"
        echo "${1}˚F = "${RES}
        exit
        ;;

-c )    shift
        RES="$(echo "scale=2; ${1}*9/5+32" | bc -q -l; printf "\b˚F")" 
        echo "${1}˚C = "${RES}
        exit
        ;;

That is:

  • Doing part of the output formatting when you create RES and the other part when you echo it is confusing, it would be better to separate
  • Printing a backspace character becomes unnecessary when you separate the calculation and display formatting of RES
  • The quoting around $(...) is unnecessary
  • Instead of echo-ing the command for bc, a here-string would be better

Like this:

RES=$(bc -q <<< "scale=2; ${1}*9/5+32")
echo "${1}˚C = ${RES}˚F"

Notice how the assignment of RES has only calculation logic, no display logic. All the display logic is on the next line. The result is cleaner and shorter.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.