2013-03-05 9 views
23

Desidero confrontare una variabile in virgola mobile con un numero intero. So che questo non è il migliore da fare con bash, ma il mio intero script è già scritto in bash. Il numero $ può essere qualsiasi numero intero. Se è inferiore o uguale a 50, voglio output1, per tutti gli altri voglio un output con l'altra variabile k. Questo è quello che ho finora:Confronto a virgola mobile con variabile in bash

number=43 
test=$(echo "scale=2; $number/50" | bc -l) 
echo "$test" 
for k in {1..5} 
do 
    if ["$test" -le 1] 
    then echo "output" 

    elif ["$test" -gt $k] 
    then echo "output$k" 
    fi 
done 

Se provo con la prova = 0,43, il primo ciclo non ha nemmeno funziona. Penso che abbia a che fare con un intero e un confronto in virgola mobile, ma non può farlo funzionare.

Qualcosa che mi manca?

PS: questo [0.43: command not found è l'output del terminale.

+0

si può anche solo passare a ksh e utilizzare tipografia a turno automaticamente. (disponibile dal 1993, funziona bene) –

risposta

43

Bash non può gestire i galleggianti. Tubo al bc invece:

if [ $(echo " $test > $k" | bc) -eq 1 ] 

L'errore che si vede, però, è perché il comando test (cioè il [) ha bisogno di spazi prima e dopo

E 'ancora meglio utilizzare ((...)) poiché si confrontano i numeri in questo modo:

if (($(bc <<< "$test > $k"))) 

la parte nel ciclo dovrebbe assomigliare a questo:

if (($(bc <<< "$test <= 1"))) 
then 
    echo "output" 
elif (($(bc <<< "$test > $k"))) 
then 
    echo "output$k" 
fi 

Le espressioni relazionali valutano a 0 se la relazione è falsa e 1 se la relazione è vera [source]. Si noti tuttavia che si tratta di un comportamento di GNU bc e non è compatibile con lo POSIX.

+1

Inoltre: bash: [: 1.3: l'espressione intera prevista sarà l'errore se hai formattato correttamente l'espressione []. + 1 @ user000001 –

+0

Grazie mille! Funziona. Piccola domanda, sto cercando di esaminare. Volevo che il primo fosse o meno o uguale a 1 e gli altri strettamente superiore a k. Posso scrivere (($ (bc <<< "$ test <1" && "$ test = 1") == 1)) o (($ (bc <<< "$ test <= 1") == 1))? – user1983400

+0

Il secondo è corretto. Il primo sarebbe corretto se hai citato in questo modo: '(($ (bc <<<" $ test <1 && $ test == 1 ") == 1))' (nore anche '=='). Per maggiori informazioni sulle espressioni booleane in 'bc' vedi qui: http://www.gnu.org/software/bc/manual/html_mono/bc.html#SEC12 – user000001

9

Tipo di una vecchia domanda, ma sopporta una risposta aggiuntiva.

Mentre eseguire il piping con un calcolatore di precisione superiore (bc o dc), è a costo di una fork e di un processo aggiuntivo, poiché tali calcolatori non sono incorporati in bash. Una cosa che è integrata, però, è printf. Quindi, se si può trattare con i numeri di essere all'interno di un particolare numero di cifre decimali, è possibile "falso" floating point confronti, con una funzione come questa:

#!/usr/bin/env bash 

function [[[() { 
    local LANG=C lhs rhs 
    printf -v lhs '%07.3f' "$1"; lhs=${lhs/./} 
    printf -v rhs '%07.3f' "$3"; rhs=${rhs/./} 
    case "$2" in 
    -lt) return $((! (10#$lhs < 10#$rhs))) ;; 
    -le) return $((! (10#$lhs <= 10#$rhs))) ;; 
    -eq) return $((! (10#$lhs == 10#$rhs))) ;; 
    -ge) return $((! (10#$lhs >= 10#$rhs))) ;; 
    -gt) return $((! (10#$lhs > 10#$rhs))) ;; 
    esac 
} 

number=${1:-43} 
test=$(dc -e "2k $number 50/p") 
echo "$test" 

for k in {1..5}; do 
    if [[[ "$test" -le 1 ]]]; then 
     echo "output" 
    elif [[[ "$test" -gt "$k" ]]]; then 
     echo "output $k" 
    fi 
done 

Un paio di cose da considerare qui.

  • Ho chiamato la funzione [[[ per essere carina. Puoi chiamarlo come preferisci. ntest o mynumericcomparison o anche [[[.
  • printf è una funzione interna in bash, quindi nonostante il fatto che sia sul tuo percorso, non costa una forchetta.
  • Così com'è, la funzione supporta numeri fino a 999.999. Se hai bisogno di numeri più alti (o più precisione), regola i formati printf.
  • L'10# all'inizio di ogni variabile all'interno dell'istruzione case consiste nel forzare il confronto a verificarsi alla base 10, poiché un numero a riempimento zero potrebbe altrimenti essere interpretato come ottale.

Consulta anche: http://mywiki.wooledge.org/BashFAQ/022

+1

Sembra abbastanza buono, ma per il gusto dei copy-pasters avrei impostato il formato 'printf' in qualcosa di più sensato (i float possono essere piuttosto lunghi e mantenere la precisione bassa non renderà questa funzione più veloce). –

Problemi correlati