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
제가 생각해낸 결과는 다음과 같습니다. 아직 노력 중이지만 예상대로 작동하는 것 같습니다. 쉘 bc
스크립트는 다음 위치 /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
(저번에 해당 기능을 어떻게 정의했습니까?).
이 모든 것은 시간이 지나면 의심할 바 없이 변하겠지만 적어도 시작은 있습니다.