Math functions from python as bash "builtins".
#!/usr/bin/env bash | |
## | |
# | |
# @author Jay E. Taylor <jay@jaytaylor.com> | |
# | |
# @description Math functions for bash! | |
# | |
## | |
_create_python_based_math_funcs() { | |
# 0-ary | |
for func in math.e math.pi ; do | |
eval " | |
${func/math\./}() { | |
python -c ' | |
import math, sys | |
sys.stdout.write(\"%s\\n\" % (${func},)) | |
' | |
} | |
export -f ${func/math\./}" || echo "ERROR: defining func '${func/math\./}'" 1>&2 | |
done | |
# unary | |
for func in int float math.acos math.acosh math.asin math.asinh math.atan math.atan2 math.atanh math.ceil math.cos math.cosh math.degrees math.factorial math.floor math.gamma math.log math.log10 math.log1p math.modf math.radians math.sin math.sinh math.sqrt math.tan math.tanh ; do | |
eval " | |
${func/math\./}() { | |
python -c ' | |
import math, sys | |
if len(sys.argv) > 1: | |
map(lambda x: sys.stdout.write(\"%s\\n\" % (${func}(float(x.strip())),)), sys.argv[1:]) | |
else: | |
for x in sys.stdin: | |
sys.stdout.write(\"%s\\n\" % (${func}(float(x.strip())),)) | |
' \"\$@\" | |
} | |
export -f ${func/math\./}" || echo "ERROR: defining func '${func/math\./}'" 1>&2 | |
done | |
# binary | |
for func in math.pow math.fmod ; do | |
eval " | |
${func/math\./}() { | |
python -c ' | |
import math, sys | |
if len(sys.argv) > 1: | |
sys.stdout.write(\"%s\\n\" % (${func}(float(sys.argv[1].strip()), float(sys.argv[2].strip())),)) | |
else: | |
x, y = None, None | |
for line in sys.stdin: | |
if x is None: | |
x = line.strip() | |
else: | |
y = line.strip() | |
if None not in (x, y): | |
if 0 not in (len(x), len(y)): | |
sys.stdout.write(\"%s\\n\" % (${func}(float(x), float(y)),)) | |
x, y = None, None | |
' \"\$@\" | |
} | |
export -f ${func/math\./}" || echo "ERROR: defining func '${func/math\./}'" 1>&2 | |
done | |
# n-ary | |
for func in min max math.fsum ; do | |
eval " | |
${func/math\./}() { | |
python -c ' | |
import math, sys | |
if len(sys.argv) > 1: | |
args = sys.argv[1:] | |
else: | |
args = sys.stdin.readlines() | |
sys.stdout.write(\"%s\\n\" % (${func}(map(lambda x: float(x.strip()), filter(lambda x: len(x.strip()) > 0, args))),)) | |
' \"\$@\" | |
} | |
export -f ${func/math\./}" || echo "ERROR: defining func '${func/math\./}'" 1>&2 | |
done | |
} | |
_create_python_based_math_funcs | |
unset _create_python_based_math_funcs | |
#echo "$@" | |
if [ "${BASH_SOURCE[0]}" = "${0}" ] && [[ "$1{:-}" =~ tests? ]] ; then | |
assert() { | |
if [ -z "${2:-}" ] ; then | |
echo 'ERROR: assert: missing operator' 1>&2 | |
echo '' 1>&2 | |
echo 'usage: assert [LHS] [OPERATOR] [RHS]' 1>&2 | |
echo '' 1>&2 | |
echo 'examples:' 1>&2 | |
echo '' 1>&2 | |
echo " assert 2 '==' 3 // \$?=0 " 1>&2 | |
echo '' 1>&2 | |
echo " assert hello '==' hello // \$?=0 " 1>&2 | |
echo '' 1>&2 | |
echo " assert 4 '>' 3" 1>&2 | |
echo ' // output: ASSERTION FAILED: $1 not == $3' 1>&2 | |
echo '' 1>&2 | |
return 1 | |
fi | |
local op | |
op="$2" | |
case "${op}" in | |
=|==|eq) | |
if [ "${1:-}" = "${3:-}" ] ; then | |
return 0 | |
fi | |
;; | |
'!='|ne) | |
if [ "${1:-}" != "${3:-}" ] ; then | |
return 0 | |
fi | |
;; | |
'<'|lt) | |
if [ "${1:-}" -lt "${3:-}" ] ; then | |
return 0 | |
fi | |
;; | |
'<='|le) | |
if [ "${1:-}" -le "${3:-}" ] ; then | |
return 0 | |
fi | |
;; | |
'>'|gt) | |
if [ "${1:-}" -gt "${3:-}" ] ; then | |
return 0 | |
fi | |
;; | |
'>='|ge) | |
if [ "${1:-}" -ge "${3:-}" ] ; then | |
return 0 | |
fi | |
;; | |
*) | |
echo "ERROR: assert: unrecognized operator: ${op}" 1>&2 | |
return 1 | |
;; | |
esac | |
echo "ASSERTION FAILED: '${1:-}' not ${op} '${3:-}'" 1>&2 | |
return 1 | |
} | |
export -f assert | |
run_module_tests() { | |
local rc | |
rc=0 | |
assert "$(min 3 4)" '==' 3.0 | |
rc=$((rc+$?)) | |
assert "$(min 3 4 | int)" '==' 3 | |
rc=$((rc+$?)) | |
assert "$(min 19 3999 24 4)" '==' 4.0 | |
rc=$((rc+$?)) | |
assert "$(min 19 -4 3999 24 | int)" '==' -4 | |
rc=$((rc+$?)) | |
assert "$(max 3 4)" '==' 4.0 | |
rc=$((rc+$?)) | |
assert "$(max 19 3999 24 4)" '==' 3999.0 | |
rc=$((rc+$?)) | |
assert "$(floor 3.50001)" '==' 3.0 | |
rc=$((rc+$?)) | |
assert "$(ceil 3.50001)" '==' 4.0 | |
rc=$((rc+$?)) | |
assert "$(float 11)" '==' 11.0 | |
rc=$((rc+$?)) | |
assert "$(int 11.5)" '==' 11 | |
rc=$((rc+$?)) | |
assert "$(pow 2 5)" '==' 32.0 | |
rc=$((rc+$?)) | |
assert "$(fsum 1 2 3 4)" '==' 10.0 | |
rc=$((rc+$?)) | |
assert "$(echo -e "-1\n0\n99\n91239\n-01249" | min | int)" '==' -1249 | |
rc=$((rc+$?)) | |
assert "$(echo -e " -1 \n 0\n99 \n 91239 \n -01249" | min | int)" '==' -1249 | |
rc=$((rc+$?)) | |
assert "$(echo '3 | |
4 | |
5 | |
6 | |
7 | |
' | min)" '==' 3.0 | |
rc=$((rc+$?)) | |
assert "$(pi)" '==' 3.14159265359 | |
rc=$((rc+$?)) | |
assert "$(echo '4 | |
5 | |
6' | fmod)" '==' 4.0 | |
rc=$((rc+$?)) | |
if [ "${rc}" -ne 0 ] ; then | |
echo "ERROR: 1 or more tests failed, rc=${rc}" 1>&2 | |
return "${rc}" | |
fi | |
echo 'INFO: All tests passed OK' 1>&2 | |
} | |
export -f run_module_tests | |
run_module_tests || echo "FAILED: test suite returned non-zero status code: $?" 1>&2 | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment