Evitare anelli nei gusci.
Se vuoi fare l'aritmetica, usa awko bc:
awk '
BEGIN{
for (i = 4.00; i < 5.42; i+ = 0.02)
print i
}'
O
bc << EOF
for (i = 4.00; i < 5.42; i += 0.02) i
EOF
Si noti che awk(contrariamente a bc) funziona con la doublerappresentazione del numero in virgola mobile dei processori (probabilmente tipo IEEE 754 ). Di conseguenza, poiché quei numeri sono approssimazioni binarie di quei numeri decimali, potresti avere alcune sorprese:
$ gawk 'BEGIN{for (i=0; i<=0.3; i+=0.1) print i}'
0
0.1
0.2
Se aggiungi un OFMT="%.17g"puoi vedere il motivo della scomparsa 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 fa precisione arbitraria, quindi non ha questo tipo di problema.
Si noti che per impostazione predefinita (a meno che non si modifichi il formato di output con OFMTo si utilizzi printfcon specifiche di formato esplicite), gli awkutilizzi %.6gper visualizzare i numeri in virgola mobile, quindi passare a 1e6 e oltre per i numeri in virgola mobile superiori a 1.000.000 e troncare la parte frazionaria per i numeri alti (100000.02 sarebbe visualizzato come 100000).
Se si ha realmente bisogno di utilizzare un ciclo di shell, perché per esempio si desidera eseguire comandi specifici per ogni iterazione di quel ciclo, utilizzare una shell con galleggianti supporto aritmetica punto, come zsh, yasho ksh93o generare l'elenco dei valori con un comando come sopra (o seqse disponibile) e scorrere sopra la sua uscita.
Piace:
unset -v IFS # configure split+glob for default word splitting
for i in $(seq 4 0.02 5.42); do
something with "$i"
done
O:
seq 4 0.02 5.42 | while IFS= read i; do
something with "$i"
done
a meno che non si spingano i limiti dei numeri in virgola mobile del processore, seqgestisce gli errori causati dalle approssimazioni in virgola mobile in modo più grazioso rispetto alla awkversione precedente.
Se non hai seq(un comando GNU), puoi renderne uno più affidabile come una funzione come:
seq() { # args: first increment last
bc << EOF
for (i = $1; i <= $3; i += $2) i
EOF
}
Funzionerebbe meglio per cose del genere seq 100000000001 0.000000001 100000000001.000000005. Nota comunque che avere numeri con precisione arbitrariamente alta non sarà di grande aiuto se li passeremo a comandi che non li supportano.