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.
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.
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:~$
Si vous avez Perl:
Perl -ne 'print eval $_,"\n"' math.txt
(J'obtiens 50000 lignes par seconde sur mon ordinateur portable en utilisant cela).
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
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
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
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.
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)"
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.
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.)