web-dev-qa-db-fra.com

Comment puis-je évaluer une équation mathématique, une par ligne dans un fichier?

J'ai un fichier avec les éléments suivants:

37 * 60 + 55.52
34 * 60 + 51.75
36 * 60 + 2.88
36 * 60 + 14.94
36 * 60 + 18.82
36 * 60 + 8.37
37 * 60 + 48.71
36 * 60 + 34.17
37 * 60 + 42.52
37 * 60 + 51.55
35 * 60 + 34.76
34 * 60 + 18.90
33 * 60 + 49.63
34 * 60 + 37.73
36 * 60 + 4.49

J'ai besoin d'écrire une commande Shell ou un script Bash qui, pour chaque ligne de ce fichier, évalue l'équation et imprime le résultat. Par exemple, pour la première ligne, je m'attends à voir 2275.52 imprimé. Chaque résultat doit être imprimé une fois par ligne.

J'ai essayé cat math.txt | xargs -n1 expr, mais cela ne fonctionne pas. Il semble également que awk pourrait être en mesure de le faire, mais je ne connais pas la syntaxe de cette commande, donc je ne sais pas ce que ce serait.

8
void.pointer

Cette awk semble faire l'affaire:

while IFS= read i; do 
  awk "BEGIN { print ($i) }"
done < math.txt

De ici

Notez que nous utilisons ($i) Au lieu de $i Pour éviter les problèmes avec des expressions arithmétiques comme 1 > 2 (print 1 > 2 Imprimerait 1 Dans un fichier appelé 2, tandis que print (1 > 2) imprime 0, le résultat de cette expression arithmétique).

Notez que puisque l'expansion de la variable Shell $i Finit par être interprétée comme code par awk, c'est essentiellement un vulnérabilité d'injection de code . Si vous ne pouvez pas garantir que le fichier ne contient que des expressions arithmétiques valides, vous souhaitez mettre en place une validation d'entrée. Par exemple, si le fichier avait une ligne system("rm -rf ~"), cela pourrait avoir des conséquences dramatiques.

13
guillermo chamorro

voici ce que je ne sais pas si c'est la meilleure méthode

bc < toto 

en fonction de ce que vous voulez faire avec les données

francois@zaphod:~$ cat > toto
37 * 60 + 55.52
34 * 60 + 51.75
36 * 60 + 2.88
36 * 60 + 14.94
36 * 60 + 18.82
36 * 60 + 8.37
37 * 60 + 48.71
36 * 60 + 34.17
37 * 60 + 42.52
37 * 60 + 51.55
35 * 60 + 34.76
34 * 60 + 18.90
33 * 60 + 49.63
34 * 60 + 37.73
36 * 60 + 4.49
francois@zaphod:~$ while read ; do echo " $REPLY" | bc  ; done < toto
2275.52
2091.75
2162.88
2174.94
2178.82
2168.37
2268.71
2194.17
2262.52
2271.55
2134.76
2058.90
2029.63
2077.73
2164.49
francois@zaphod:~$

sans commande BC, vous ne pouvez pas utiliser de valeurs décimales:

francois@zaphod:~$ while read ; do echo $(( "REPLY" )) ; done < toto
-bash: 37 * 60 + 55.52: syntax error: invalid arithmetic operator (error token is ".52")
francois@zaphod:~$
8
francois P

Si vous avez Perl:

Perl -ne 'print eval $_,"\n"' math.txt

(J'obtiens 50000 lignes par seconde sur mon ordinateur portable en utilisant cela).

7
Ole Tange

Avec old-good Python:

$ python -c $'import sys;\nfor line in sys.stdin:print(eval(line))' <math.txt
2275.52
2091.75
2162.88
2174.94
2178.82
2168.37
2268.71
2194.17
2262.52
2271.55
2134.76
2058.9
2029.63
2077.73
2164.49
4
RomanPerekhrest

Si vous avez seulement besoin des résultats, j'aurais obtenu la réponse fournie par @ francois-p

Pour le plaisir et les jeux, ajoutez paste et sed:

$ paste <(sed 's/\($\)/\1\t=/g' somefile) <(bc < somefile)
37 * 60 + 55.52 =   2275.52
34 * 60 + 51.75 =   2091.75
36 * 60 + 2.88  =   2162.88
36 * 60 + 14.94 =   2174.94
36 * 60 + 18.82 =   2178.82
36 * 60 + 8.37  =   2168.37
37 * 60 + 48.71 =   2268.71
36 * 60 + 34.17 =   2194.17
37 * 60 + 42.52 =   2262.52
37 * 60 + 51.55 =   2271.55
35 * 60 + 34.76 =   2134.76
34 * 60 + 18.90 =   2058.90
33 * 60 + 49.63 =   2029.63
34 * 60 + 37.73 =   2077.73
36 * 60 + 4.49  =   2164.49
3
markgraf

Avec Perl:

Perl -ple '$_=eval' ex
Perl -nE 'say eval' ex

avec Python:

python3 -qi < ex
python3 -qic 'import sys; sys.ps1=""' < ex

Avec Haskell:

ghci < ex
ghci < ex | grep -Po '> \S+$'

Avec calc:

calc -f ex      # apt install apcalc if necessary
3
JJoao

directement dans bash/ksh ( Edit: Il s'avère que bash ne peut pas faire cela, seulement ksh - merci de l'avoir signalé):

$ while read l
> do
> echo $(($l))
> done <<!
> 37 * 60 + 55.52
> 34 * 60 + 51.75
> 36 * 60 + 2.88
> 36 * 60 + 14.94
> 36 * 60 + 18.82
> 36 * 60 + 8.37
> 37 * 60 + 48.71
> 36 * 60 + 34.17
> 37 * 60 + 42.52
> 37 * 60 + 51.55
> 35 * 60 + 34.76
> 34 * 60 + 18.90
> 33 * 60 + 49.63
> 34 * 60 + 37.73
> 36 * 60 + 4.49
> !
2275.52
2091.75
2162.88
2174.94
2178.82
2168.37
2268.71
2194.17
2262.52
2271.55
2134.76
2058.9
2029.63
2077.73
2164.49

Cela peut nécessiter une version assez récente de votre Shell - $((...)) utilisée uniquement pour faire de l'arithmétique entière.

2
j4nd3r53n

Utilisation de awk/python:

python -c "$(awk '{printf "print %s;", $0}' math.txt)"

awk est utilisé ici pour formater votre fichier en une entrée qui python acceptera, puis python fait le travail).

Alternativement, Perl peut être utilisé à peu près de la même manière:

Perl -le "$(awk '{printf "print %s;", $0}' math.txt)"
2
jesse_b

Directement avec awk:

awk '{ printf "%f\n", $0 }' math.txt

Le $0 représente la ligne entière lue ligne par ligne dans le fichier.

De plus, il n'est pas sensible aux injections désagréables. Il n'évaluera qu'une ligne comme un nombre à virgule flottante.

1
Klaas van Aarsen

Alimentez simplement le désordre avec bc -l, il retournera un résultat de ligne pour chaque ligne d'expression. (Le -l charge la bibliothèque mathématique, il définit également scale à une valeur plus élevée et donne ainsi des résultats fractionnaires.)

0
vonbrand