Solved sh shell variables by reference

I'm not an expert about programming sh script and I run in trouble when I try to understand what happens in a big shell script (like portmaster). What I wish to do is writing functions with writable variables in parameters. I make an example:
Bash:
#! /bin/sh

varResult=0

# Add two numbers and put result in a variable (by reference)
# Params:
#    $1    first number
#    $2    second number
#    $3    [ref] result
addFunc ()
{
    local num1 num2 result
    if [ "$#" -ne "3" ]; then
        echo "wrong params"
        return 1
    fi
    num1=$1
    num2=$2
    result=$3
    $result=$(( num1 + num2 ))
    return 0
}

# Main
addFunc "6" "4" "varResult"
echo "6 + 4 = $varResult"

I hope this example explain what I was say. Executing it give the result:
Code:
/root/bin/test.sh: varResult=10: not found
6 + 4 = 0
 
Code:
    result=$3
    $result=$(( num1 + num2 ))
This doesn't do what you think it does, you need to eval(1) it.
Code:
    result=$3
    eval "$result=$(( num1 + num2 ))"

Code:
dice@molly:~/temp % ./test.sh
6 + 4 = 10
 
There doesn't seem to be a FreeBSD man page with a description for eval.
It's a shell builtin. Granted, the explanation in sh(1) is rather terse too. It doesn't provide much clues on how to use it or what you can do with it.

Code:
     eval string ...
             Concatenate all the arguments with spaces.  Then re-parse and
             execute the command.
 
my take using getopts for checking the arguments
and bc for calculations

Code:
#!/bin/sh

#===============================================================================
# number
# add two numbers
#===============================================================================

# dependencies:
# bc

#===============================================================================
# script usage
#===============================================================================

usage () {
# if argument passed to function echo it
[ -z "${1}" ] || echo "! ${1}"
# display help
echo "\
add two numbers
$(basename "$0") -f 1 -s 2"
exit 2
}


#===============================================================================
# error messages
#===============================================================================

INVALID_OPT_ERR='Invalid option:'
REQ_ARG_ERR='requires an argument'
WRONG_ARGS_ERR='wrong number of arguments passed to script'


#===============================================================================
# check the number of arguments passed to the script
#===============================================================================

[ $# -gt 0 ] || usage "${WRONG_ARGS_ERR}"


#===============================================================================
# getopts check the options passed to the script
#===============================================================================

while getopts ':f:s:h' opt
do
  case ${opt} in
     f) first="${OPTARG}";;
     s) second="${OPTARG}";;
     h) usage;;
     \?) usage "${INVALID_OPT_ERR} ${OPTARG}" 1>&2;;
     :) usage "${INVALID_OPT_ERR} ${OPTARG} ${REQ_ARG_ERR}" 1>&2;;
  esac
done
shift $((OPTIND-1))


#===============================================================================
# function
#===============================================================================

numberadd () {
printf "%s %s %s\n" "${first}" "+" "${second}" | bc
}


#===============================================================================
# run function
#===============================================================================

numberadd

run the script

Code:
./number -f 20 -s 23.5

output

Code:
43.5

help

Code:
./number -h

Code:
add two numbers
number -f 1 -s 2

run without any arguments

Code:
./number

Code:
! wrong number of arguments passed to script
add two numbers
number -f 1 -s 2

forgetting to pass an argument

Code:
./number -f 1 -s

Code:
! Invalid option: s requires an argument
add two numbers
number -f 1 -s 2

invalid option

Code:
./number -f 1 -x 3

Code:
! Invalid option: x
add two numbers
number -f 1 -s 2
 
Back
Top