1

I've searched for this but can't find anything more than some basic tutorials or posts.

What I'm trying to do is a more sophisticated calculator (without using bc) that can take more than 2 arguments. something like:

./calc.sh 2 + 3 * 7 - 2 ^ 3

My attempt was as follow:

  • search for operator
  • if operator is ^ or * do the math and replace 2 ^ 2 + 3 * 2 - 2 becomes 4 + 6 -2
  • add remains to the list
  • next loop checks for : and does the math, same follows for + and -

this leads me to the creation of this piece of "code" but after running it I've realized that there are some major issues with it and swapping deleting items isn't that straightforward to me

#!/bin/bash

initial_data=($@)
result=0

sorted=()

for ((index=0; index <= ${#initial_data[@]}; index++)); do
  
  if [ "${initial_data[index]}" == "^" ]; then
    A=${initial_data[index-1]}
    B=${initial_data[index+1]}
    pow_value=$(($A**$B))
    sorted+=$pow_value

  elif [ "${initial_data[index]}" == "*" ]; then 
    C=${initial_data[index-1]}
    D=${initial_data[index+1]}
    multi_value=`expr $C \* $D`
    sorted+=$multi_value

  else
    normal=${initial_data[index]}
    sorted+=$normal
  fi
done
echo ${sorted[@]}

then I've scraped this and tried something that goes like this

operators=('^' '*' '/' '+' '-')

data=("$@")
ops=()
for i in "${!data[@]}"; do
    if (printf '%s\n' "${operators[@]}" | grep -xq ${data[$i]}); then
        ops+=("${data[$i-1]} ${data[$i]} ${data[$i+1]}")
    fi  
done
declare -p ops 

This isn't that bad. It takes the order of operators but I didn't account for odd amount of numbers feed into calc and it doesn't see exponentiation.

I’m bit over my head.

Biffen
  • 6,249
  • 6
  • 28
  • 36
stud1234
  • 65
  • 7
  • 6
    `./calc.sh 2 + 3 * 7 - 2 ^ 3` will never work: The interactive shell (the one the user is typing the command into) will change the `*` to a list of filenames before the shell executing the script is even started. – Charles Duffy Nov 04 '21 at 15:48
  • Beyond that -- `expr` is an artifact of the 1970s and should never be used in modern code: Since 1992, the POSIX standard has included arithmetic expansion. But that still may not be good enough for your use case if you need to do floating-point math, because both `expr` and arithmetic expansion do integer math only. – Charles Duffy Nov 04 '21 at 15:50
  • 1
    And beyond _that_, if you're going to respect arithmetic precedence, you want a real parser that can build an AST; bash is the wrong tool for the job. – Charles Duffy Nov 04 '21 at 15:51
  • 1
    (Also, you're missing quotes in places where they aren't optional; `initial_data=($@)` has all the bugs of `initial_data=($*)`; if you want anything different, it needs to be `initial_data=( "$@" )`). – Charles Duffy Nov 04 '21 at 15:52
  • If you don't want to worry about parsing for precedence, then you should switch from accepting arithmetic expressions in infix syntax to either prefix or postfix so you can implement a stack machine; takes all the parsing out of the job. – Charles Duffy Nov 04 '21 at 15:53
  • I greatly appreciate your comments. I know about the * or rather \* and I know that expr is old but schools don't care about that. I need to it in this way or I will fail the class – stud1234 Nov 04 '21 at 16:10
  • Does "in some way" include using a preexisting calculator that the OS already ships with? `dc` is a thing. – Charles Duffy Nov 04 '21 at 16:12
  • @stud1234 do you need to respect arithmetic precedence? – Michael Jaros Nov 04 '21 at 16:15
  • @CharlesDuffy yes, I need to it all by hand, that wasn't be the problem but we can't use python – stud1234 Nov 04 '21 at 16:16
  • @MichaelJaros Yeah, calculator without arithmetic precedence isn't a great calculator – stud1234 Nov 04 '21 at 16:18
  • one idea to get around Charles Duffy comment re: `./calc.sh 2 + 3 * 7 - 2 ^ 3` expanding the `*` into a list of files ... instead of providing the equation on the command line consider prompting the user for the equation, eg, `read -p 'enter equation: ' data`, then make sure you always reference the variable in double quotes - `"${data}"` – markp-fuso Nov 04 '21 at 16:23
  • 3
    Honestly, this is a place where the guidance in [How do I ask and answer homework questions?](https://meta.stackoverflow.com/a/334823/14122) is appropriate. A question should be about a specific technical problem you encountered doing your assignment yourself, not something so broadly scoped that it comes down to "how do I solve this assignment?". Showing what you tried is helpful, but _not_ asking a specific question about a narrow problem to be fixed (in particular, narrower than "how do I solve this assignment?")... less so. – Charles Duffy Nov 04 '21 at 16:23
  • I think a good CLI calculator, designed for interactive use, and that takes a variable number of args like you describe (reminds me of the way `googler(1)` takes queries) would be useful and popular. I made a short, hacky wrapper script named `c`, for `bc`, to get an interface exactly like you’re describing, and I use it nearly every day. I made `x` be a multiply operator, `-l` default, and a few other things. – dan Nov 04 '21 at 16:37
  • 1
    without knowing what you've covered (in class) so far re: parsers, or assumptions you're making on the format of user inputs, it's hard to make any explicit rec's; I'd suggest doing some web surfing for related articles, eg, `computer algorithm parse numeric equation` opens up a really big search area ... near the top I see this [SO Q&A re: parsing and precendence](https://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence) that may provide some ideas ... ? – markp-fuso Nov 04 '21 at 16:47

1 Answers1

1

The only thing you need to calculate is the result of the power, the rest you can do as follows:

echo $((2 + 3 * 7 - 2*2*2))
Dominique
  • 16,450
  • 15
  • 56
  • 112
  • 1
    alternatively `**` works for the power operator (I'm not sure if some version is needed) – ti7 Nov 04 '21 at 16:45