Last active
August 16, 2020 05:01
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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