Skip to content

Instantly share code, notes, and snippets.

@jaytaylor
Created August 8, 2019 21:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaytaylor/1166da29fab464c69662b36de61907bd to your computer and use it in GitHub Desktop.
Save jaytaylor/1166da29fab464c69662b36de61907bd to your computer and use it in GitHub Desktop.
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