3
votes

Comment forcer AWK à évaluer la chaîne en tant qu'expression mathématique?

Existe-t-il un moyen d'évaluer une chaîne en tant qu'expression mathématique dans awk?

balter@spectre3:~$ echo "sin(0.3) 0.3" | awk '{print $1,sin($2)}'
sin(0.3) 0.29552

Je voudrais savoir un moyen d'évaluer également la première entrée à 0,29552.


4 commentaires

Que diriez-vous d'utiliser cet echo "sin (0.3) 0.3" | awk '{match ($ 1, / \ (. * \) /); print sin (substr ($ 1, RSTART + 1, RLENGTH-1)), sin ($ 2)}' :) Je sais que vous voulez le faire passer comme une expression MATH (dont je ne suis pas conscient pour le moment, en regardant les documentations), a pensé une façon amusante de jouer avec celle-ci.


Eh bien, il y a la version étendue du script awk calc3 par Kenny McCormack et Alan Linton qui flotte autour des internets, voici un lien: groups.google.com/forum / #! topic / comp.lang.awk / C4SbutsY1JA L'original calc3 < / code> ne supportait que les opérations de base, mais celui lié semble gérer le péché et autres.


echo "sin (0.3)" | awk -f calc3.awk produit sin (0.3) = 0.29552


echo "sin (0.3) 0.3" | perl -ne '/ (\ S +) \ s + (\ S +) / et print eval ($ 1), "", $ 2' fonctionneraient également.


5 Réponses :


3
votes

awk n'a pas de fonction eval (...) . Cela signifie que vous ne pouvez pas effectuer de traduction de chaîne en code basée sur l'entrée après l'initialisation du programme awk. Ok, peut-être que cela pourrait être fait, mais pas sans écrire votre propre moteur d'analyse et d'évaluation dans awk.

Je recommanderais d'utiliser bc pour cet effort, comme

[edwbuck@phoenix ~]$ echo "s(0.3)" | bc -l
.29552020666133957510


5 commentaires

++ ve pour solution. Moi aussi j'ai pensé la même chose (ajouté un commentaire avec la solution) si OP avait besoin de le faire toujours en awk uniquement :)


Pourquoi n'y a-t-il pas de bibliothèque mathématique en ligne de commande sensée pour Linux? Ma solution actuelle est m () {python -c "import math; print ($ 1);} . Je pourrais aussi utiliser perl. Mon ancien patron l'a vu et m'a dit que je venais de construire les mondes calculatrice la plus chère.


@abalter Je pensais que bc était pour la calculatrice de base et satisfaisait le besoin de "maths en ligne de commande sains"; mais, les moyens de faire des mathématiques sous Linux ne manquent pas. Je reconnais que s (..) et c (...) sont des manières étranges d'écrire sin et cos , c'est dommage qu'ils n'aient pas opté pour sin (...) et cos () . De plus, on pourrait presque utiliser l'approche echo $ (($ expr)) de bash, sauf qu'elle ne prend pas en charge trig.


@EdwinBuck Fait intéressant, POSIX limite les noms de fonction et de variable en bc à une seule lettre. (Bien que des implémentations multi-lettres soient disponibles)


@abalter wrt Pourquoi n'y a-t-il pas de bibliothèque mathématique en ligne de commande sensée pour Linux? - parce que ce n'est pas à quoi sert un shell. Un shell est un environnement à partir duquel appeler des outils et dispose d'un petit langage pour aider à séquencer ces appels. Il n'est pas destiné / conçu pour être un langage de programmation complet et si vous essayez de l'utiliser en tant que tel, vous manquez le point.



3
votes

Vous pouvez simplement créer votre propre fonction eval qui appelle à nouveau awk pour exécuter la commande que vous voulez:

$ cat tst.awk
{ print eval($1), sin($2) }

function eval(str,      cmd,line,ret) {
    cmd = "awk \047BEGIN{print " str "; exit}\047"
    if ( (cmd | getline line) > 0 ) {
        ret = line
    }
    close(cmd)
    return ret
}

$ echo 'sin(0.3) 0.3' | awk -f tst.awk
0.29552 0.29552

$ echo '4*7 0.3' | awk -f tst.awk
28 0.29552

$ echo 'tolower("FOO") 0.3' | awk -f tst.awk
foo 0.29552


0 commentaires

1
votes

Avec la version 4.1.2 de gawk:

echo "sin(0.3) 0.3" | awk '{split($1,a,/[()]/);f=a[1];print @f(a[2]),sin($2)}'

Cela fonctionne aussi avec tolower (FOO) .


1 commentaires

Bonne idée pour les appels de fonction qui acceptent des arguments numériques ou de chaîne simples (vous ne pouvez tout simplement pas l'utiliser avec 4 * 7 ou index ("abc", "b") ou sin (0,1 + 0,2) par exemple). btw [(] | [)] = [()] .



0
votes

Vous pouvez essayer Perl car il a la fonction eval ().

$ echo "sin(0.3) 0.3" | perl -ne ' /(\S+)\s+(\S+)/ and print eval($1), " ", $2 '
0.29552020666134 0.3
$

Pour l'entrée donnée,

$  echo "sin(0.3)" | perl -ne ' print eval '
0.29552020666134
$


0 commentaires

2
votes

Voici une simple doublure!

x=100; y=5; math "sqrt($x) + $y"

Exemples d'utilisation:

math 'sqrt(25)'

Rend "2"

math 1+1  

Yeilds "5"

math(){ awk "BEGIN{printf $1}"; }

Yeilds "15"


0 commentaires