Ever get tired of trying to do math in bash?

Issues and / or general discussion relating to Puppy

Moderator: Forum moderators

Post Reply
User avatar
Jafadmin
Posts: 385
Joined: Tue Aug 04, 2020 4:51 pm
Has thanked: 68 times
Been thanked: 85 times

Ever get tired of trying to do math in bash?

Post by Jafadmin »

Firstly, 'bc' is cool. But sometimes it can take most of a cold beer to figure out how to get it to understand what I'm trying to do. The other problem is that ' if [ $NumVar > 0 ]; then blah blah ..; fi' will often have the hidden side effect of creating all those wierd little files you see from time to time named '1' or '0' with nothing in them.

So .. I wrote a utility in C called 'decx' (decimal worx). It doesn't use standard math operators. Instead it uses alphabet operators similar to a -gt, -lte type of operator, but in uppercase and no dash is needed. Why? To keep from confusing bash. It does decimal comparisons, and decimal math. You can specify the precision you prefer (default is 1)

So attached is a tar.gz file with the C source and a simple bash testing script. Take a look at the code, compile on your machine, stick it in your my-applications/bin, and have fun with it.

- jafadmin

decx.tar.gz
(1.72 KiB) Downloaded 26 times

[Update] Guys I don't need advice on how to write shell scripts. I've been doing it since the 80's. On more different types of shells than I care to mention. On more different OS's than I care to mention. I've been writing C code even longer. But thanks :thumbup2:

Last edited by Jafadmin on Sun Jun 04, 2023 6:51 pm, edited 3 times in total.
User avatar
BarryK
Posts: 2748
Joined: Tue Dec 24, 2019 1:04 pm
Has thanked: 136 times
Been thanked: 750 times

Re: Ever get tired of trying to do math in bash?

Post by BarryK »

How would that differ from a version-compare utility?
The pup-tools pet in EasyOS has 'vercmp':

Code: Select all

# vercmp --help
usage: vercmp version1 lt|gt|le|ge|eq version2
       return value 0 if true, else 1

64-bit pet:
http://distro.ibiblio.org/easyos/amd64/ ... pyro64.pet

Source:
http://distro.ibiblio.org/easyos/source ... 101.tar.gz

So you can do something like this:

Code: Select all

if vercmp 1.2.3 gt 0.5; then
 echo ok
fi
User avatar
Jafadmin
Posts: 385
Joined: Tue Aug 04, 2020 4:51 pm
Has thanked: 68 times
Been thanked: 85 times

Re: Ever get tired of trying to do math in bash?

Post by Jafadmin »

It does floating point math and negative values

decx -89.1 T 32
-2851.2

decx -89.1 LT 32
0

decx 37.69911 D 12 -p=8 # :thumbup2:
3.14159250

Burunduk
Posts: 257
Joined: Thu Jun 16, 2022 6:16 pm
Has thanked: 7 times
Been thanked: 127 times

Re: Ever get tired of trying to do math in bash?

Post by Burunduk »

((2>1)) && echo yes || echo no doesn't create files.

But if it's for bash, why putchar and not an exit code?

User avatar
Jafadmin
Posts: 385
Joined: Tue Aug 04, 2020 4:51 pm
Has thanked: 68 times
Been thanked: 85 times

Re: Ever get tired of trying to do math in bash?

Post by Jafadmin »

Burunduk wrote: Sat Jun 03, 2023 6:05 am

((2>1)) && echo yes || echo no doesn't create files.

But if it's for bash, why putchar and not an exit code?

It does do exit codes. So we need to do both. exit code AND a result. decx does comparisons AND math operations.

echo `decx 34.025 T .003 -p=4` ('T' means x)
0.1021

It's purpose is to do both floating point comparisons AND math. Without using standard math operators. Standard math operators also have non-math functions in *nix shells. 'bc' does great, but it relies on standard math operators which can be misinterpreted by the shell.

If you have never encountered this problem, that is great. But it does happen. With annoying regularity.

This came about as a result of a project I have been working on that wgets xml packets which contains decimal math data. This 'decx' approach greatly simplifies the data conversion and the essential floating point math which needs to be performed.

Burunduk
Posts: 257
Joined: Thu Jun 16, 2022 6:16 pm
Has thanked: 7 times
Been thanked: 127 times

Re: Ever get tired of trying to do math in bash?

Post by Burunduk »

Your program always returns 0 (unless an error occurs), meanwhile test returns 0 if the condition is true, 1 - if false, and 2 on error.
With decx doing the same, it would be possible to write simply decx $num1 LT $num2 && echo yes || echo no
insread of [ $(decx $num1 LT $num2) = 0 ] && echo yes || echo no

And to simplify [ $(decx $num1 LT $(decx $num1 T $num2)) = 0 ] && echo yes || echo no you could use something like this:

Code: Select all

#!/bin/bash

declare -A map=( [GT]='>' [LT]='<' [GE]='>=' [LE]='<=' \
  [EQ]='==' [NE]='!=' [A]='+' [S]='-' [M]='*' [D]='/' )

expression=
for p; do
  if [[ $p =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
    expression+="$p"
  elif [[ ${map["${p^^}"]} ]]; then
    expression+=${map["${p^^}"]}
  else
    exit 2
  fi
done

res=`echo "$expression" | bc -l`

echo $res
[ ! $res = 0 ]

For example, if this script is saved as bcx, then bcx $num1 lt $num1 m $num2 && echo yes || echo no

It's easy to port it to other shells but it's not that easy to do in c. Maybe this can be used: https://github.com/codeplea/tinyexpr
It doesn't look very tiny though.

User avatar
Jafadmin
Posts: 385
Joined: Tue Aug 04, 2020 4:51 pm
Has thanked: 68 times
Been thanked: 85 times

Re: Ever get tired of trying to do math in bash?

Post by Jafadmin »

Burunduk wrote: Sat Jun 03, 2023 7:59 pm

Your program always returns 0 (unless an error occurs), meanwhile test returns 0 if the condition is true, 1 - if false, and 2 on error.
With decx doing the same, it would be possible to write simply decx $num1 LT $num2 && echo yes || echo no
insread of [ $(decx $num1 LT $num2) = 0 ] && echo yes || echo no

And to simplify [ $(decx $num1 LT $(decx $num1 T $num2)) = 0 ] && echo yes || echo no you could use something like this:

Code: Select all

#!/bin/bash

declare -A map=( [GT]='>' [LT]='<' [GE]='>=' [LE]='<=' \
  [EQ]='==' [NE]='!=' [A]='+' [S]='-' [M]='*' [D]='/' )

expression=
for p; do
  if [[ $p =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
    expression+="$p"
  elif [[ ${map["${p^^}"]} ]]; then
    expression+=${map["${p^^}"]}
  else
    exit 2
  fi
done

res=`echo "$expression" | bc -l`

echo $res
[ ! $res = 0 ]

For example, if this script is saved as bcx, then bcx $num1 lt $num1 m $num2 && echo yes || echo no

It's easy to port it to other shells but it's not that easy to do in c. Maybe this can be used: https://github.com/codeplea/tinyexpr
It doesn't look very tiny though.

Now change the first line of the script (#!/bin/bash) to (#!/bin/sh) and see if it runs.

Here is the thing about C. It is the most portable programming language on the planet. That code I posted will run on every flavor of Unix, linux, and every other unix flavored operating system. It will compile and run on Windows. It will compile and run on Macs. It will compile and run on Android. It will behave exactly the same on each platform. Heck, it will compile and run on OS400.

That's the point. It isn't life changing. It is useful. And portable to any OS with a C compiler. That is the point of C. Portability.
One of the things I learned while studying programming was that there are 10 ways to write code to solve a problem. 5 will be useful, and the other 5 will be more trouble than they are worth.

One of the drawbacks to shell programming is that shells differ. C is a standard.

The code is FOSS so do with it what you will.

User avatar
MochiMoppel
Posts: 1245
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 22 times
Been thanked: 446 times

Re: Ever get tired of trying to do math in bash?

Post by MochiMoppel »

Jafadmin wrote: Fri Jun 02, 2023 11:42 pm

The other problem is that ' if [ $NumVar > 0 ]; then blah blah ..; fi' will often have the hidden side effect of creating all those wierd little files you see from time to time named '1' or '0' with nothing in them.

That's because your syntax is wrong. Your code writes an empty string to a file named "0", creates it if it doesn't exist. Certainly not what you intended, but exactly what you instructed bash to do.

With double brackets it would work. It would evaluate the alphabetic sort order of the arguments instead of treating them as numbers:
[[ 333.1234 > 044.56 ]] && echo true || echo false
true

[[ 333.1234 > 444.56 ]] && echo true || echo false
false

The integer parts must have same lenghts (hence the zero padding) and it works only with positive numbers. Lenght is only limited by bash's string lenght limit (~124K ?) and not by bash's integer limit.
And no, I don't endorse it and have never used it. Still there might be cases where it can serve as a quick, dirty (and fake) arithmetic comparison.

User avatar
Jafadmin
Posts: 385
Joined: Tue Aug 04, 2020 4:51 pm
Has thanked: 68 times
Been thanked: 85 times

Re: Ever get tired of trying to do math in bash?

Post by Jafadmin »

MochiMoppel wrote: Sun Jun 04, 2023 5:37 am
Jafadmin wrote: Fri Jun 02, 2023 11:42 pm

The other problem is that ' if [ $NumVar > 0 ]; then blah blah ..; fi' will often have the hidden side effect of creating all those wierd little files you see from time to time named '1' or '0' with nothing in them.

That's because your syntax is wrong. ...

Yep. Ever had that happen? Yep. That's the point. As a SE I prefer to spend less time on syntax and more time on algorythms.

It is certainly possible to eventually get there with a shell script and bc. My complaint is that like the arcane awk/sed/perl syntax, it can become burdensome to try to read and comprehend what is supposed to be happening. Especially when trying to work with real math in scripts.

I completely understand that "it works if you do it right". That doesn't need to be said. The same can be said of parkour and billiards. But like the aforementioned sports, doing it right is 98% of the story.

Being able to craft tools to ease the burden is what makes us human. Creating a 100% portable solution to handle the math parkour is preferable to playing whackamole with hieroglyphic shell syntax.

ps. It isn't my shell scripts creating the amusing artifacts in the file system. I just notice them.

User avatar
Jafadmin
Posts: 385
Joined: Tue Aug 04, 2020 4:51 pm
Has thanked: 68 times
Been thanked: 85 times

Re: Ever get tired of trying to do math in bash?

Post by Jafadmin »

BarryK wrote: Sat Jun 03, 2023 1:05 am

How would that differ from a version-compare utility?
The pup-tools pet in EasyOS has 'vercmp':

Code: Select all

# vercmp --help
usage: vercmp version1 lt|gt|le|ge|eq version2
       return value 0 if true, else 1

64-bit pet:
http://distro.ibiblio.org/easyos/amd64/ ... pyro64.pet

Source:
http://distro.ibiblio.org/easyos/source ... 101.tar.gz

So you can do something like this:

Code: Select all

if vercmp 1.2.3 gt 0.5; then
 echo ok
fi

here is the problem:

Code: Select all

[ 0 == 0.0 ] && echo sure || echo nope

In decimal math, that should evaluate to true

Post Reply

Return to “Users”