Évitez les boucles dans les coquilles.
Si vous voulez faire de l'arithmétique, utilisez awk
ou bc
:
awk '
BEGIN{
for (i = 4.00; i < 5.42; i+ = 0.02)
print i
}'
Ou
bc << EOF
for (i = 4.00; i < 5.42; i += 0.02) i
EOF
Notez que awk
(contrairement à bc
) fonctionne avec la représentation numérique à double
virgule flottante de votre processeur (probablement de type IEEE 754 ). Par conséquent, puisque ces nombres sont des approximations binaires de ces nombres décimaux, vous pouvez avoir quelques surprises:
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
Si vous ajoutez un, OFMT="%.17g"
vous pouvez voir la raison de la disparition 0.3
:
$ gawk 'BEGIN{OFMT="%.17g"; for (i=0; i<=0.5; i+=0.1) print i}'
0
0.10000000000000001
0.20000000000000001
0.30000000000000004
0.40000000000000002
0.5
bc
fait une précision arbitraire donc n'a pas ce genre de problème.
Notez que par défaut (sauf si vous modifiez le format de sortie avec OFMT
ou utilisez printf
des spécifications de format explicites), awk
utilise %.6g
pour afficher les nombres à virgule flottante, donc passerait à 1e6 et au-dessus pour les nombres à virgule flottante supérieurs à 1000000 et tronquer la partie fractionnaire pour les nombres élevés (100000.02 serait affiché comme 100000).
Si vous avez vraiment besoin d'utiliser une boucle shell, par exemple parce que vous voulez exécuter des commandes spécifiques pour chaque itération de cette boucle, soit utiliser une coque avec support arithmétique en virgule flottante comme zsh
, yash
ou ksh93
ou générer la liste des valeurs avec une commande comme ci - dessus (ou seq
si disponible) et boucle sur sa sortie.
Comme:
unset -v IFS # configure split+glob for default word splitting
for i in $(seq 4 0.02 5.42); do
something with "$i"
done
Ou:
seq 4 0.02 5.42 | while IFS= read i; do
something with "$i"
done
sauf si vous repoussez les limites des nombres à virgule flottante de votre processeur, seq
gère les erreurs encourues par les approximations à virgule flottante plus gracieusement que ne le awk
ferait la version ci-dessus.
Si vous n'en avez pas seq
(une commande GNU), vous pouvez en faire une plus fiable comme une fonction comme:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
Cela fonctionnerait mieux pour des choses comme seq 100000000001 0.000000001 100000000001.000000005
. Notez cependant qu'avoir des nombres avec une précision arbitraire élevée n'aidera pas beaucoup si nous allons les passer à des commandes qui ne les prennent pas en charge.