我想以m4
交互方式使用作为bc
.我的直接用例是添加一项include
功能bc
,但我可以预见将来的其他用途。但有一个问题。这是一个bc
单独使用的示例:
$ bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
3+7
10
sqrt(12345)
111
quit
$
这是交互式使用的相同示例m4
:
$ m4 -iP - | bc
3+7
10
sqrt(12345)
111
quit
$
有两点不同。首先,m4
版本打压了横幅。其次,该m4
版本不会quit
立即执行,而是需要在执行quit
.
为什么会出现这些事情呢?如何使m4
版本与版本一样工作bc
?
答案1
这是我想到的,尽管我仍在尝试,但它似乎按我预期的方式工作。 shellbc
脚本位于/usr/local/bin/bc
以下$PATH
位置/usr/bin/bc
:
#! /bin/sh
HELP="usage: /usr/local/bin/bc [options] [file ...]
-h print usage message and exit
-s synclines; same as m4 -s
-v print bc version information and exit
-D name[=value] define macro name, optionally give it a value
-I directory location of m4 include directory
-U name undefine macro name
NOTE: bc -ql are always active; bc -sw are unavailable;
m4 -P is always active; m4 -i may be active"
USAGE="-[hsv] [-D name[=value]] [-I directory] [-U name]\n"
# file locations
BC=/usr/bin/bc
BCPRE=/usr/local/bin/bc.prelude
M4=/usr/bin/m4
M4PRE=/usr/local/bin/bc.m4.prelude
SCRIPT="./bc.script.$(date +%Y%m%d)"
# collect command options
M4OPTS=""
while getopts "hsvD:I:U:" flag
do case $flag in
h) echo "$HELP"; exit 0;; # print help message and exit
s) M4OPTS="$M4OPTS -s";; # synclines
v) $BC -v; exit 0;; # print bc version and exit
D) M4OPTS="$M4OPTS -D $OPTARG";; # define macro name[=value]
I) M4OPTS="$M4OPTS -I $OPTARG";; # specify include directory
U) M4OPTS="$M4OPTS -U $OPTARG";; # undefine macro name
?) echo "Usage: $0 $USAGE"; exit 2;;
esac
done
shift $(($OPTIND - 1))
# initialize random number generator
SRAND=$(mktemp /tmp/bc.srand.XXXXXX)
echo "srand = $(od -vAn -N4 -tu4 < /dev/urandom)" > $SRAND
trap "rm -f $SRAND" 0 1 2 3 15
# execute bc
if test -t 0
then script -qfa bc.script.$(date +%Y%m%d) -c \
"rlwrap -aN sh -c \"$M4 -iP $M4PRE $SRAND $BCPRE $@ - | $BC -ql\""
else $M4 -P $M4PRE $SRAND $BCPRE $@ - | $BC -ql
fi
这是bc.prelude
:
scale = 0; ibase = obase = A
define int(x) { # truncate toward zero
auto s; s = scale; scale = 0; x /= 1; scale = s; return x }
define frac(x) { return x - int(x) }
define abs(x) { if (x<0) return -x else return x }
define sgn(x) { if (x<0) return -1; if (x>0) return 1; return 0 }
define max(a,b) { if (a<b) return b else return a }
define min(a,b) { if (a<b) return a else return b }
define mod(n,m) {
auto x, s; s = scale; scale = 0; x = n % m; scale = s
if (x < 0) return x + m; return x }
define gcd(a,b) {
auto x, s; s = scale; scale = 0
while (b != 0) { x = mod(a,b); a = b; b = x }
scale = s; return a }
define push(*stack[],value) { return(stack[++stack[0]]=value) }
define pop(*stack[]) {
if (stack[0]<1) stack[-1] else return stack[stack[0]--] }
define srand(seed) { # seed on half-open range [0,2^32)
auto i, old_scale; old_scale = scale; scale = 0; srand[0] = seed
for (i=1; i<32; i++) # initialize shuffle box
srand = srand[i] = (69069 * srand[i-1] + 1234567) % 4294967296
scale = old_scale; return seed }
junk = srand(srand) # initial seed from /dev/urandom via bc shell script
define rand() { # pseudorandom integer on half-open range [0,2^32)
auto j, n, old_scale; old_scale = scale; scale = 0
srand = (69069 * srand + 1234567) % 4294967296
n = srand[(j = 32 * srand / 4294967296)]
srand[j] = srand; scale = old_scale; return n }
define randint(lo,hi) { # pseudorandom integer from lo to hi inclusive
auto randint, old_scale; old_scale = scale; scale = 0
randint = (hi - lo + 1) * rand() / 4294967296 + lo
scale = old_scale; return randint }
这是bc.m4.prelude
:
m4_divert(-1)
m4_define(error, `{ print $1, "\n"; 0/0 }')
m4_define(with_scale,
{ junk = push(saved_scale[],scale); scale = $1;
$2;
scale = pop(saved_scale[]) })
m4_define(load, `m4_include($1)')
m4_define(quit, `m4_m4exit')
m4_divert`'m4_dnl
以下是与 的交互示例bc
:
$ bc
rand()
2525043732
with_scale(20,a(1)*4)
3.14159265358979323844
define fib(n) {
auto f1, f2, f3
f1 = 0; f2 = 1
while (n-- > 0) {
f3 = f1 + f2
f1 = f2; f2 = f3 }
return f2 }
fib(37)
39088169
quit
$
命令历史记录readline
似乎工作正常,我希望自动收集记录(每天一个文件,bc
同一文件中有多个会话)将非常有用(前几天我是如何定义该函数的?)。
所有这些无疑都会随着时间而改变,但至少我有一个开始。