Je veux faire une boucle for en bash avec 0,02 comme incréments que j'ai essayé
for ((i=4.00;i<5.42;i+=0.02))
do
commands
done
mais ça n'a pas marché.
bash
for
floating-point
Mehrshad
la source
la source
bc
, mais l'arrêt sur 4,52 peut être délicat. utiliser la suggestion @roaima, avoir une var auxiliaire avec un pas de 2 et utiliseri=$(echo $tmp_var / 100 | bc)
Réponses:
La lecture de la
bash
page de manuel donne les informations suivantes:puis nous obtenons cette section
On voit donc clairement que vous ne pouvez pas utiliser une
for
boucle avec des valeurs non entières.Une solution peut être simplement de multiplier tous vos composants de boucle par 100, ce qui permet de les utiliser ultérieurement, comme ceci:
la source
k=400;k<542;k+=2
car cela évite également d'éventuels problèmes d'arithmétique en virgule flottante.bc
), créez un processus, créez un fichier temporaire (pour la chaîne ici), exécutez-bc
le (ce qui implique de charger un exécutable et des bibliothèques partagées et les initialiser), attendez et nettoyez. Courirbc
une fois pour faire la boucle serait beaucoup plus efficace.i=$(bc <<< "scale...")
oui=$(echo "scale..." | bc)
<<<
vient),bash
etksh
. Notez que le passage à un autre shellbash
vous donnera une meilleure amélioration des performances que l'utilisation de l'autre syntaxe.<<<
(zsh, mksh, ksh93, Yash) prennent également en charge arithmétiques en virgule flottante (zsh
,ksh93
,yash
)).Évitez les boucles dans les coquilles.
Si vous voulez faire de l'arithmétique, utilisez
awk
oubc
:Ou
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:Si vous ajoutez un,
OFMT="%.17g"
vous pouvez voir la raison de la disparition0.3
: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 utilisezprintf
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
ouksh93
ou générer la liste des valeurs avec une commande comme ci - dessus (ouseq
si disponible) et boucle sur sa sortie.Comme:
Ou:
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 leawk
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: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.la source
unset IFS
dans le premier exemple?IFS=$'\n'
mais cela ne fonctionne pas dans tous les shells. OuIFS='<a-litteral-newline-here>'
mais ce n'est pas très lisible. Ou nous pouvons diviser les mots à la place (espace, tabulation, nouvelle ligne) comme vous obtenez avec la valeur par défaut de $ IFS ou si vous désactivez IFS et fonctionne également ici.IFS
, car nous savons queseq
la sortie de n'a pas d'espaces sur lesquels nous devons éviter de nous séparer. Il est principalement là pour vous assurer que vous comprenez que cet exemple dépendIFS
, ce qui pourrait avoir une importance pour une commande de génération de liste différente.Utiliser "seq" - imprimer une séquence de chiffres
SEQ PREMIER INCREMENT DERNIER
la source
Comme d'autres l'ont suggéré, vous pouvez utiliser bc:
la source