Unikaj pętli w muszlach.
Jeśli chcesz wykonywać arytmetykę, użyj awk
lub bc
:
awk '
BEGIN{
for (i = 4.00; i < 5.42; i+ = 0.02)
print i
}'
Lub
bc << EOF
for (i = 4.00; i < 5.42; i += 0.02) i
EOF
Zauważ, że awk
(w przeciwieństwie do bc
) współpracuje z procesorami double
reprezentacji liczb zmiennoprzecinkowych (prawdopodobnie typu IEEE 754 ). W rezultacie, ponieważ te liczby są binarnymi przybliżeniami tych liczb dziesiętnych, możesz mieć pewne niespodzianki:
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
Jeśli dodasz OFMT="%.17g"
, możesz zobaczyć przyczynę braku 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
wykonuje dowolną precyzję, więc nie ma tego rodzaju problemów.
Zauważ, że domyślnie (chyba że zmienisz format wyjściowy za pomocą OFMT
lub użyjesz printf
jawnych specyfikacji formatu), awk
używa %.6g
do wyświetlania liczb zmiennoprzecinkowych, więc przełącza się na 1e6 i więcej dla liczb zmiennoprzecinkowych powyżej 1 000 000 i obcina część ułamkową dla wysokich liczb (100000,02 będzie wyświetlany jako 100000).
Jeśli naprawdę potrzebujesz użyć pętli powłoki, ponieważ na przykład chcesz uruchomić określone polecenia dla każdej iteracji tej pętli, użyj powłoki z obsługą arytmetyki zmiennoprzecinkowej zsh
, yash
lub, ksh93
lub wygeneruj listę wartości za pomocą jednego polecenia, jak powyżej (lub seq
jeśli jest dostępny) i zapętlić jego wynik.
Lubić:
unset -v IFS # configure split+glob for default word splitting
for i in $(seq 4 0.02 5.42); do
something with "$i"
done
Lub:
seq 4 0.02 5.42 | while IFS= read i; do
something with "$i"
done
o ile nie przekroczysz limitów liczb zmiennoprzecinkowych procesora, obsługa seq
błędów wynikających z przybliżeń zmiennoprzecinkowych jest bardziej płynna niż w przypadku awk
wersji powyżej.
Jeśli nie masz seq
(polecenia GNU), możesz uczynić je bardziej niezawodnym jako funkcja:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
To działałoby lepiej w przypadku takich rzeczy seq 100000000001 0.000000001 100000000001.000000005
. Zauważ jednak, że posiadanie liczb z dowolnie wysoką precyzją niewiele pomoże, jeśli przekażemy je poleceniom, które ich nie obsługują.