Je veux calculer une expression en shell. J'utilise le code suivant:
pi=$(echo "scale=10; 4*a(1)" | bc -l) i=3 d=`expr (1+c($pi*($i/10)+$pi))/2 | bc -l`
Mais ça dit
bad pattern: (1+c(3.1415926532*(3/10)+3.1415926532))/2
Pourquoi?
Parce que vous utilisez expr
dans votre dernière command où vous devriez probablement utiliser echo
.
PS Je vous conseille d'utiliser la forme $(…)
dans les deux commands bc
(plutôt que `…`
).
Si vous prenez mon conseil, vous n'utiliserez pas “ ou $()
– c'est un peu bête. bc
est un interprète interactif, orienté vers la ligne. Il lit dans une ligne de stdin, vérifie s'il en a besoin d'un autre en fonction de l'input qui vient d'être lue, puis imprime ses résultats sur stdout ou request plus sur stdin. Comme votre shell, il refusera même de faire quoi que ce soit de plus qu'une sortie ligne-tampon même si elle est écrite sur un autre terminal qu'un terminal. Il n'y a aucun besoin d'appeler un nouveau bc
pour chaque calcul – en particulier dans une substitution de command qui implique également d'appeler un tout nouveau shell et d'allouer un nouveau tube.
Le meilleur moyen est de mettre en place un co-process.
# in a bash shell exec 8<> >( : ) 9< <( bc <&8 ) echo 'b=5;++b' >&8 read b <&9 echo "$b"
6
Et le bc
continuera simplement à fonctionner – toutes ces valeurs de variables que vous faites tellement de travail pour faire la navette entre les process bc
éphémères, commandés par command, pourraient être plus facilement stockées de manière centralisée dans un bc
central.
echo b\*b >&8; read b <&9; echo "$b"
32
Et encore mieux, depuis que j'ai appris comment faire cela l'autre jour, vous pouvez mettre le process bc
sur un server socket.
{ ncat -l 9000 --allow localhost -k| bc; } <>/dev/fd/1 |:&
Et avec un shell qui parle le langage /dev/tcp
:
{ echo 'b=10;b' >&0; read b; echo "$b"; } <>/dev/tcp/localhost/9000
10
Cela peut devenir un peu encombrant. J'ai écrit une petite fonction appelée bchat()
pour le rendre plus facile.
bchat(){ local IFS=\; ### separate on ; printf ${1+'%s;"\n"\n';}"$*" ### print \0 if no args set -- ### init args while read bchat && ### while read <bc "${bchat:+set}" -- "$@" "${bchat:=$*}" ### append to args do :; done 2>/dev/null ### and done } <>"$BC" >&0 ### $BC must be set
Après avoir configuré un server socket comme indiqué ci-dessus, vous pouvez utiliser cette fonction comme:
BC=/dev/tcp/localhost/9000 bchat b=5 x='(b--)' '"x="' ++x '"b="' --b echo "$bchat"
x=6;b=3
… et encore, cet état persistera aussi longtime que le process BC …
Méfiez-vous que lorsque vous définissez l'échelle a une influence sur le calcul.
Ce script:
bc -l << \EOF scale = 10 pi = 4 * a(1) i = 3 (1 + c(pi * (i / 10) + pi)) / 2 EOF bc -l << \EOF pi = 4 * a(1) i = 3 scale = 10 (1 + c(pi * (i / 10) + pi)) / 2 EOF bc -l << \EOF pi = 4 * a(1) i = 3 r = (1 + c(pi * (i / 10) + pi)) / 2 scale = 10 r/1 EOF bc -l << \EOF scale = 100 pi = 4 * a(1) i = 3 r = (1 + c(pi * (i / 10) + pi)) / 2 scale = 15 r/1 EOF
les sorties:
.2061073736 .2061073739 .2061073738 .206107373853763