Skip to content

Instantly share code, notes, and snippets.

@h8rt3rmin8r
Last active August 16, 2020 05:01
Show Gist options
  • Save h8rt3rmin8r/13b6161678024ce2899d20e41d279c1b to your computer and use it in GitHub Desktop.
Save h8rt3rmin8r/13b6161678024ce2899d20e41d279c1b to your computer and use it in GitHub Desktop.
Math shell (mshell) is a general purpose math handling script written for native Bash
#! /usr/bin/env bash
#>------------------------------------------------------------------------------
#>
#> [ mshell ]
#>
#> Math shell (mshell) is a math handling script written for native Bash
#>
#> USAGE:
#>
#> mshell <TYPE> (<INPUT> ... <INPUT>)
#>
#> where "INPUT" is determined by "TYPE"; and where "TYPE" is one of the
#> following:
#>
#> |
#> --abs | Return the absolute value of one or more input numbers
#> |
#> --add | Add two or more floating point numbers together
#> |
#> --avg | Calculate the average of all input numbers
#> |
#> --com | Check if a number is greater than or less than another
#> | number using an expression formatted in one of the two
#> | following ways:
#> |
#> | "X < Y" or "X > Y"
#> |
#> | where "X" and "Y" are both real numbers.
#> |
#> | NOTE: When passing greater-than and less-than characters
#> | in Bash, be sure to quote the entire expression, otherwise
#> | Bash will think you are running a "here" doc operation.
#> |
#> | Outputs are formatted as either "TRUE" or "FALSE".
#> |
#> --div | Divide a primary input by one or more other inputs; all
#> | subsequent input values after the second input cause a
#> | recursive division to be calculated, taking an input
#> | from the previous value's output
#> |
#> --is-higher | Compare two numbers and output the larger of the two
#> |
#> --is-lower | Compare two numbers and output the smaller of the two
#> |
#> --mlt | Multiply a number by one or more other numbers; all
#> | subsequent input values after the second input cause a
#> | recursive multiplication to be calculated, taking an
#> | input from the previous value's output
#> |
#> --ran | Generate pseudo random numbers of an optionally-specified
#> | length; if no length is specified the default output will
#> | be exactly five characters in length
#> |
#> --rou | Round a number to a specified number of digits
#> |
#> | The total number of numeric values contained in the
#> | output is found without respect to decimal placement.
#> |
#> | This operation requires exactly one or two inputs:
#> |
#> | <NUMBER_TO_EVALUATE> <PRECISION>
#> |
#> | NOTE: Numbers must be inside quotes if they include a
#> | decimal. If only one number is passed, rounding will
#> | occur up to the one's place after a decimal (resulting
#> | in a non-decimal output).
#> |
#> --sub | Subtract floating point numbers; all subsequent inputs
#> | after the second input cause a recursive subtraction to
#> | be calculated, taking an input from the previous value's
#> | output
#> |
#>
#> Unless otherwise indicated, all "INPUT" values may be passed either
#> directly or by a space-delimited incoming pipe.
#>
#> -------------------------------------------------------------------------
#>
#> mshell <OPTION>
#>
#> where "OPTION" is one of the following:
#>
#> |
#> -h, --help | Print this help text to the terminal (STDOUT)
#> |
#>
#> ATTRIBUTION:
#>
#> Created on 20200815 by h8rt3rmin8r ([email protected])
#>
#> SOURCE:
#>
#> # Pastebin
#> https://pastebin.com/kgXaC5rv
#>
#> # Github
#> https://gist.github.com/h8rt3rmin8r/13b6161678024ce2899d20e41d279c1b
#>
#> REFERENCE:
#>
#> # Floating Point Math in Bash (linuxjournal.com)
#> https://www.linuxjournal.com/content/floating-point-math-bash
#>
#>------------------------------------------------------------------------------
# Declare functions
function ms_help() {
# Script help text function
cat "${0}" \
| grep -E '^#[>]' \
| sed 's/^..//'
return $?
}
function ms_run_abs() {
# Absolute value function
for i in ${IN_ARR[@]}; do
echo "${i//[-]}"
done
return $?
}
function ms_run_add() {
# Addition function
dc -e "0 ${IN_ARR[*]/-/_} ${IN_ARR[*]/*/+} p" 2>/dev/null
return $?
}
function ms_run_avg() {
# Numeric average function
local IN_COUNT="${#IN_ARR[@]}"
local VALUE=$(dc -e "0 ${IN_ARR[*]/-/_} ${IN_ARR[*]/*/+} p" 2>/dev/null)
echo "scale=10; ${VALUE} / ${IN_COUNT} " \
| bc 2>/dev/null
return $?
}
function ms_run_com() {
# Numeric comparison function
if [[ "x${IN_ARR[0]}" == "x" ]]; then
return 1
elif [[ ! "${IN_ARR[@]}" =~ [\<\>] || ! "${IN_ARR[@]}" =~ [0-9] ]]; then
return 1
fi
local c_d=0
if [[ "${#IN_ARR[@]}" -gt 0 ]]; then
set -f
c_d=$(echo "$@" | bc -q 2>/dev/null)
if [[ -z "$c_d" ]]; then
c_d=0
fi
if [[ "$c_d" != 0 && "$c_d" != 1 ]]; then
c_d=0
fi
set +f
fi
local e_c=$((c_d == 0))
if [[ "${e_c}" -eq 0 ]]; then
echo "TRUE"
return 0
else
echo "FALSE"
return 1
fi
}
function ms_run_div() {
# Division function
if [[ "${#IN_ARR[@]}" -gt 2 ]]; then
local result=""
while [[ "${#IN_ARR[@]}" -gt 0 ]]; do
if [[ "x${result}" == "x" ]]; then
local result=$(echo "${IN_ARR[0]} / ${IN_ARR[1]}" | bc -l 2>/dev/null)
local e_c="$?"
local IN_ARR=(${IN_ARR[@]:2})
else
local result=$(echo "${result} / ${IN_ARR[0]}" | bc -l 2>/dev/null)
local e_c="$?"
local IN_ARR=(${IN_ARR[@]:1})
fi
done
echo "${result}"
else
echo "${IN_ARR[0]} / ${IN_ARR[1]}" \
| bc -l 2>/dev/null
local e_c="$?"
fi
return ${e_c}
}
function ms_run_ishigher() {
# Higher number discovery function
if [[ "${#IN_ARR[@]}" -ne 2 ]]; then
return 1
fi
local lesser_num=$(dc -e "[${IN_ARR[0]}]sM ${IN_ARR[1]}d ${IN_ARR[0]}<Mp")
if [[ "${lesser_num}" == "${IN_ARR[0]}" ]]; then
echo "${IN_ARR[1]}"
else
echo "${IN_ARR[0]}"
fi
return $?
}
function ms_run_islower() {
# Lower number discovery function
if [[ "${#IN_ARR[@]}" -ne 2 ]]; then
return 1
fi
local lesser_num=$(dc -e "[${IN_ARR[0]}]sM ${IN_ARR[1]}d ${IN_ARR[0]}<Mp")
if [[ "${lesser_num}" == "${IN_ARR[0]}" ]]; then
echo "${IN_ARR[0]}"
else
echo "${IN_ARR[1]}"
fi
return $?
}
function ms_run_mlt() {
# Multiplication function
if [[ "${#IN_ARR[@]}" -gt 2 ]]; then
local result=""
while [[ "${#IN_ARR[@]}" -gt 0 ]]; do
if [[ "x${result}" == "x" ]]; then
local result=$(echo "${IN_ARR[0]} * ${IN_ARR[1]}" | bc -l 2>/dev/null)
local e_c="$?"
local IN_ARR=(${IN_ARR[@]:2})
else
local result=$(echo "${result} * ${IN_ARR[0]}" | bc -l 2>/dev/null)
local e_c="$?"
local IN_ARR=(${IN_ARR[@]:1})
fi
done
echo "${result}"
else
echo "${IN_ARR[0]} * ${IN_ARR[1]}" \
| bc -l 2>/dev/null
local e_c="$?"
fi
return ${e_c}
}
function ms_run_ran() {
# Random number generation funciton
local out_len="${IN_ARR[0]}"
## Verify the presence of a valid length specifier
if [[ ! "${out_len}" =~ ^[0-9]+$ ]]; then
local out_len=5
fi
cat /dev/urandom \
| tr -dc '0-9' \
| fold -w ${out_len} \
| head -n 1
return $?
}
function ms_run_rou() {
# Number rounding function
local in_count="${#IN_ARR[@]}"
if [[ "${in_count}" -ne 2 ]]; then
if [[ "${in_count}" -eq 1 ]]; then
local in_a="${IN_ARR[0]}"
local in_a_prefix="${in_a//.*}"
local in_a_prefix_size="${#in_a_prefix}"
local in_b="${in_a_prefix_size}"
else
return 1
fi
else
local in_a="${IN_ARR[0]}"
local in_b="${IN_ARR[1]}"
fi
local n=$(printf "%.${in_b}g" "${in_a}")
if [[ "$n" != "${n#*e}" ]]; then
local f="${n##*e-}"
test "$n" = "$f" && f= || f=$(( ${f#0}+$1-1 ))
local output=$(printf "%0.${f}f" "$n")
else
local output=$(printf "%s" "$n")
fi
echo "${output}"
return $?
}
function ms_run_sub() {
# Subtraction function
local IN_ARR_MOD=(${IN_ARR[@]:1})
local X_1="${IN_ARR[0]}"
local X_2=$(dc -e "0 ${IN_ARR_MOD[*]/-/_} ${IN_ARR_MOD[*]/*/+} p" 2>/dev/null)
echo "scale=11; ${X_1} - ${X_2} " \
| bc 2>/dev/null
return $?
}
function ms_valid_ops() {
declare -f "${1}" &>/dev/null
local e_c="$?"
echo "${e_c}"
return ${e_c}
}
# Parse inputs and execute operations
if [[ "${1}" == "-h" || "${1}" =~ ^[-]+help$ ]]; then
ms_help
exit $?
fi
if [ -t 0 ]; then
in_type_pre="${1//[-]}"
in_type="ms_run_${in_type_pre}"
shift 1
declare -a IN_ARR=( $@ )
else
in_type_pre="${1//[-]}"
in_type="ms_run_${in_type_pre}"
shift 1
declare -a IN_ARR=( $(cat -) )
fi
## Validate the requested operation to make sure it exists
ops_check=$(ms_valid_ops "${in_type}")
if [[ "${ops_check}" -ne 0 ]]; then
exit 1
fi
## Execute the requested operation with all input values submitted as
## the array "IN_ARR"
${in_type}
exit $?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment