Evite loops nas conchas.
Se você deseja fazer aritmética, use 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
Observe que awk
(ao contrário de bc
) funciona com a double
representação do número de ponto flutuante dos seus processadores (provavelmente do tipo IEEE 754 ). Como resultado, como esses números são aproximações binárias desses números decimais, você pode ter algumas surpresas:
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
Se você adicionar um, OFMT="%.17g"
poderá ver o motivo da falta 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
faz precisão arbitrária e não tem esse tipo de problema.
Observe que, por padrão (a menos que você modifique o formato de saída com OFMT
ou use printf
especificações de formato explícitas), awk
use %.6g
para exibir números de ponto flutuante, portanto, alternaria para 1e6 e acima para números de ponto flutuante acima de 1.000.000 e truncaria a parte fracionária para números altos (100000.02 seria exibido como 100000).
Se você realmente precisa usar um loop shell, porque, por exemplo, você deseja executar comandos específicos para cada iteração desse loop, use um shell com flutuante apoio aritmética de ponto como zsh
, yash
ou ksh93
ou gerar a lista de valores com um comando como acima (ou, seq
se disponível) e faça um loop sobre sua saída.
Gostar:
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
a menos que você ultrapasse os limites dos números de ponto flutuante do processador, seq
lida com os erros incorridos pelas aproximações de ponto flutuante com mais graciosidade do que a awk
versão acima.
Se você não possui seq
(um comando GNU), pode torná-lo mais confiável como uma função como:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
Isso funcionaria melhor para coisas como seq 100000000001 0.000000001 100000000001.000000005
. Observe, no entanto, que ter números com precisão arbitrariamente alta não ajudará muito se vamos passá-los para comandos que não os suportam.