Search code examples
bashbc

"bc" external tool into a function


"Despite producing floating point results. Bash does not support other type of arguments than integers, so you need to rather invoke external tools like bc for your math or stick to integers only." 4.5: syntax error: invalid arithmetic operator (error token is ".5") - but the code still seems to work, why? Usually I use the bc external tool to fix it, but now I have a function and I do not know where to use it exactly, can you help me?

    #!/bin/bash

function crossProduct {
  declare -a v1=("${!1}")
  declare -a v2=("${!2}") 

#Note:  Can't pass by reference, so the global variable must be used
  vectResult[0]=$(( (v1[1] * v2[2]) - (v1[2] * v2[1]) ))
  vectResult[1]=$(( - ((v1[0] * v2[2]) - (v1[2] * v2[0])) ))
  vectResult[2]=$(( (v1[0] * v2[1]) - (v1[1] * v2[0]) ))
}

vect1[0]=0.3
vect1[1]=-0.3
vect1[2]=0.1

vect2[0]=0.4
vect2[1]=0.9
vect2[2]=2.3

crossProduct vect1[@] vect2[@]
echo ${vectResult[0]} ${vectResult[1]} ${vectResult[2]}

Solution

  • You can pass references, namely as local -n arr=$1:

    $ function _tmp {
        local -n arr=$1
        for i in ${arr[@]}; do echo $i; done
    }
    $ TMP=(1 2 3)
    $ _tmp TMP
    1
    2
    3
    

    Now to the bc question; it parses a string and returns the value of it. Therefore you should use it as:

    # make sure you declare vectResult first.
    
    function crossProduct {
      declare -a v1=("${!1}")
      declare -a v2=("${!2}") 
    
      vectResult[0]=$( echo "(${v1[1]} * ${v2[2]}) - (${v1[2]} * ${v2[1]}) " | bc)
      vectResult[1]=$( echo "- ((${v1[0]} * ${v2[2]}) - (${v1[2]} * ${v2[0]}))" | bc )
      vectResult[2]=$( echo "(${v1[0]} * ${v2[1]}) - (${v1[1]} * ${v2[0]})" | bc )
    }
    

    Combining the two as how I would implement it:

    #!/bin/bash
    
    function crossProduct {
        local -n v1=$1
        local -n v2=$2
        local result=()
    
        # You should remain to use bc because Bash only does integers. 
        result+=($( echo "(${v1[1]} * ${v2[2]}) - (${v1[2]} * ${v2[1]}) " | bc))
        result+=($( echo "-((${v1[0]} * ${v2[2]}) - (${v1[2]} * ${v2[0]}))" | bc ))
        result+=($( echo "(${v1[0]} * ${v2[1]}) - (${v1[1]} * ${v2[0]})" | bc ))
        echo "${result[@]}"
    }
    
    vect1[0]=0.3
    vect1[1]=-0.3
    vect1[2]=0.1
    
    vect2[0]=0.4
    vect2[1]=0.9
    vect2[2]=2.3
    
    vectResult=($(crossProduct vect1 vect2))
    echo ${vectResult[0]} ${vectResult[1]} ${vectResult[2]}
    exit 0
    

    This produces -.6 -.6 .3