| #!/usr/bin/env bash | |
| # bash 4.2.24(1) Linux Ubuntu 12.04 Date : 2012-09-13 | |
| # | |
| # _______________| aw : use awk as quick custom calculator on command line. | |
| # | |
| # Usage: aw 'expression' [decimal/sig:8] [format:g] | |
| # aw bak # show log file of previous result. | |
| # | |
| # | |
| # User-defined: r = random number strictly between 0 and 1, | |
| # never 0 nor 1, see rand(). | |
| # s = stored full result from previous script call. | |
| # pi, e. | |
| # mil, bil, tri; pc, bp, milli, macro, nano. | |
| # [ Also add your favorite functions. ] | |
| # [ Recommended format choices are e, f, or g. ] | |
| # | |
| # Examples: % aw '(3+2)*r' | |
| # 4.63147 # random real between 0 and 5. | |
| # % aw r 0 f | |
| # 1 # random integer, 0 or 1. | |
| # % aw '10 * pc * 210' | |
| # 21.0000 # 10% of 210 | |
| # % aw 's/2' | |
| # 10.5000 # take half of previous result. | |
| # | |
| # Dependencies: gawk (on Ubuntu 12.04 prefer installing "gawk" package | |
| # since inferior mawk of 1996 is the default awk.) | |
| # This script will use system's awk if gawk is unavailable. | |
| # | |
| # Definitive REFERENCE by Arnold Robbins, "gawk: Effective AWK Programming", | |
| # http://www.gnu.org/software/gawk/manual/ (2011) | |
| # | |
| # WARNING: Unassigned variables in awk are given value of 0. | |
| # Thus do not misspell variable names!! | |
| # | |
| # Exponentiation: the character sequence ** is equivalent to ^. | |
| # exp() is available; and the constant e is defined in the script. | |
| # log() is the natural logarithm. | |
| # int() is integer truncation. | |
| # Functions: sqrt, sin, cos, and atan2 are also available in gawk. | |
| # CHANGE LOG LATEST version available: https://bitbucket.org/rsvp/gists/src | |
| # 2012-09-13 Add variable for awkprg, in case gawk is unavailable. | |
| # printf modified for portability. | |
| # Replace both head and tail by sed for portability. | |
| # Memorialize first argument on memf's third line. | |
| # 2012-09-10 Add printf format as third argument. | |
| # Shadow the full result into storage. | |
| # 2012-09-09 First version using gawk 3.1.8 under Ubuntu 12.04, | |
| # script patterned on pye. gawk is 12% the size of Python. | |
| # Fixed awk's seed for randomness problem. | |
| # _____ PREAMBLE_v2: settings, variables, and error handling. | |
| # | |
| LC_ALL=POSIX | |
| # locale means "ASCII, US English, no special rules, | |
| # output per ISO and RFC standards." | |
| # Esp. use ASCII encoding for glob and sorting characters. | |
| shopt -s extglob | |
| # ^set extended glob for pattern matching. | |
| shopt -s failglob | |
| # ^failed pattern matching signals error. | |
| set -e | |
| # ^errors checked: immediate exit if a command has non-zero status. | |
| set -u | |
| # ^unassigned variables shall be errors. | |
| # Example of default VARIABLE ASSIGNMENT: arg1=${1:-'foo'} | |
| ndec=${2:-'8'} | |
| # ^default number of significant or decimal places. | |
| # ndec=0 gives rounded integer result [unlike int()], but | |
| # see printf section below for important rounding caveats. | |
| letter=${3:-'g'} | |
| # ^control printf format, e.g. e, f, g -- for | |
| # exponent, float, or mixture with max significant digits. | |
| program=${0##*/} # similar to using basename | |
| # memf=$( mktemp /dev/shm/88_${program}_tmp.XXXXXXXXXX ) | |
| memf="/dev/shm/88_${program}_tmp" | |
| # ^intended to persist, to save last result. | |
| cleanup () { | |
| # Delete temporary files, then optionally exit given status. | |
| local status=${1:-'0'} | |
| # rm -f $memf | |
| [ $status = '-1' ] || exit $status # thus -1 prevents exit. | |
| } #-------------------------------------------------------------------- | |
| warn () { | |
| # Message with basename to stderr. Usage: warn "message" | |
| echo -e "\n !! ${program}: $1 " >&2 | |
| } #-------------------------------------------------------------------- | |
| die () { | |
| # Exit with status of most recent command or custom status, after | |
| # cleanup and warn. Usage: command || die "message" [status] | |
| local status=${2:-"$?"} | |
| cleanup -1 && warn "$1" && exit $status | |
| } #-------------------------------------------------------------------- | |
| trap "die 'SIG disruption, but cleanup finished.' 114" 1 2 3 15 | |
| # Cleanup after INTERRUPT: 1=SIGHUP, 2=SIGINT, 3=SIGQUIT, 15=SIGTERM | |
| # | |
| # _______________ :: BEGIN Script :::::::::::::::::::::::::::::::::::::::: | |
| if ( which gawk > /dev/null ) ; then | |
| awkprg='gawk' | |
| else | |
| # warn "gawk is not installed. Falling back on system's awk." #-DEBUG | |
| awkprg='awk' | |
| # Ubuntu 12.04 awk defaults to inferior mawk. | |
| fi | |
| # Retrieve result from previous execution: | |
| if [ -s $memf ] ; then | |
| stored="$( sed -n -e '2p' $memf )" | |
| # ^pick out the second printf from gawk output. | |
| if [ "$1" = 'bak' ] ; then | |
| cat $memf | |
| cleanup | |
| fi | |
| else | |
| stored=0 | |
| # ^expected awk behavior. | |
| fi | |
| #-------------------------------------- awk at work... | |
| { $awkprg -f - <<EOHereDoc | |
| BEGIN { | |
| s = "$stored" | |
| e = 2.718281828459045 | |
| pi = 3.141592653589793 | |
| mil = 1000000 | |
| bil = 1000000000 | |
| tri = 1000000000000 | |
| pc = 0.01 | |
| milli = 0.001 | |
| bp = 0.0001 | |
| macro = 0.000001 | |
| nano = 0.000000001 | |
| srand( $(date '+%N') ) | |
| # ^To SEED the random generator, | |
| # awk by default uses time which does not change for 1 sec, | |
| # thus executions during that second gives the same output. | |
| # Our FIX is to use the nanoseconds portion of time | |
| # which looks like 877928409 -- nine digits. | |
| # Execution of aw one nanosecond apart generates, e.g. | |
| # 0.5656 | |
| # 0.1706 | |
| # 0.2621 | |
| # 0.2180 | |
| # 0.0804 | |
| # 0.7866 | |
| # So it looks like the neighborhood problem is avoided. | |
| } | |
| function pch (x, y) { | |
| # percentage change | |
| return ( (y-x)/x )*100 | |
| } | |
| # There is no middle section { } | |
| # because that is for evalating each record. | |
| # Of course, we have no records here! | |
| END { | |
| r = rand() | |
| # ^ one-time convenient random number variable. | |
| # It costs virtually nothing in execution time. | |
| evala = ( $1 ) | |
| # ^ evaluated argument from command line. | |
| printf "%.${ndec}${letter}\n", evala | |
| #-X printf "%1\$.${ndec}${letter}\n", evala # OK on gawk, not on mawk. | |
| # Floating-point with ndec number of decimal places. | |
| # ___ATTN___ printf does NOT round the decimal portion. | |
| # For ndec=0, we do not get integer truncation. | |
| # Rounding is "unbiased," which means it doesn't always round | |
| # a trailing '.5' up, contrary to naive expectations. | |
| # In unbiased rounding, '.5' rounds to even, rather than always up, | |
| # so 1.5 rounds to 2 but 4.5 rounds to 4. See | |
| # http://www.gnu.org/software/gawk/manual/html_node/Round-Function.html | |
| # which provide the usual rounding function. | |
| # | |
| # CONVFMT's default value is "%.6g", which yields a value | |
| # with at least six significant digits. | |
| printf "%.15e\n", evala | |
| #-X printf "%1\$.15e\n", evala # OK on gawk, not on mawk. | |
| # SECOND printf reports the FULL version for storage, | |
| # since the first printf may not have fully expressed | |
| # the complete result due to user formatting. | |
| } | |
| EOHereDoc | |
| } > $memf | |
| # Preserve TWO results into memory. | |
| #-------------------------------------- awk done. | |
| # Show just the requested format result on STDOUT, | |
| # i.e. the first printf within awk. | |
| sed -n -e '1p' $memf | |
| #-X head -n1 $memf # replaced for portability. | |
| echo "$1" >> $memf | |
| # memorialize first argument on memf's third line. | |
| cleanup | |
| # _______________ EOS :: END of Script :::::::::::::::::::::::::::::::::::::::: | |
| # vim: set fileencoding=utf-8 ff=unix tw=78 ai syn=sh : |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment