Bardzo się staram porównać dwie liczby zmiennoprzecinkowe w skrypcie bash. Mam do zmiennych np
let num1=3.17648e-22
let num2=1.5
Teraz chcę tylko zrobić proste porównanie tych dwóch liczb:
st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
Niestety mam pewne problemy z odpowiednim traktowaniem num1, który może mieć „e-format”. :(
Każda pomoc, podpowiedzi są mile widziane!
Odpowiedzi:
Wygodniej
Można to zrobić wygodniej, korzystając z kontekstu numerycznego Basha:
Wyjaśnienie
Przepływ przez podstawowe polecenie kalkulatora
bc
zwraca 1 lub 0.Ta opcja
-l
jest równoważna--mathlib
; ładuje standardową bibliotekę matematyczną.Umieszczenie całego wyrażenia w podwójnym nawiasie
(( ))
spowoduje przetłumaczenie tych wartości odpowiednio na prawdę lub fałsz.Upewnij się, że
bc
jest zainstalowany podstawowy pakiet kalkulatora.Działa to również w przypadku pływaków w formacie naukowym, pod warunkiem użycia dużej litery
E
, npnum1=3.44E6
źródło
bc
zainstalowany pakiet kalkulatora.0: not found
z oświadczeniemif (( $(echo "$TOP_PROCESS_PERCENTAGE > $THRESHOLD" | bc -l) )); then
.bc
w jeden z apostrofów lub,$()
a następnie w(( ))
… tj.(( $(bc -l<<<"$a>$b") ))
I nie(( bc -l<<<"$a>$b" ))
.E
, a wszystkie błędy składniowe znikną.bash obsługuje tylko liczby całkowite, ale możesz użyć
bc
polecenia w następujący sposób:Zauważ, że znak potęgi musi być pisany wielką literą
źródło
bc
narzędzie i to właśnie poleciłbym każdemu programiście BASH. BASH jest językiem bez typu. Tak, może wykonywać arytmetykę na liczbach całkowitych, ale dla zmiennoprzecinkowych musisz użyć jakiegoś zewnętrznego narzędzia. BC jest najlepsza, ponieważ do tego jest stworzona.Lepiej jest używać
awk
do matematyki niecałkowitej. Możesz użyć tej funkcji narzędzia bash:I nazwij to:
źródło
awk
ibc
w skryptach powłoki jest standardową praktyką od czasów starożytnych, powiedziałbym, że niektóre funkcje nigdy nie zostały dodane do powłok, ponieważ są dostępne w awk, bc i innych narzędziach Uniksa. Nie ma potrzeby zachowania czystości w skryptach powłoki.exit
tak aby Awk przekazał wynik z powrotem do powłoki we właściwy, czytelny dla komputera sposób.if awk -v n1="123.456" -v n2="3.14159e17" 'BEGIN { exit (n1 <= n2) }' /dev/null; then echo bigger; else echo not; fi
... jednak zwróć uwagę, jak warunek jest odwrócony (kod wyjścia 0 oznacza powodzenie powłoki).python
. Maszperl
domyślnie instalowany na wielu systemach Linux / Unix .. nawetphp
takżeawk
rozwiązanie jest bardziej niezawodne w moim przypadku niż to,bc
które zwraca nieprawidłowe wyniki z powodu, którego nie dostałem.Czyste rozwiązanie bash do porównywania liczb zmiennoprzecinkowych bez wykładniczej notacji, wiodących lub końcowych zer:
Kolejność operatorów logicznych ma znaczenie . Części całkowite są porównywane jako liczby, a części ułamkowe są celowo porównywane jako łańcuchy. Za pomocą tej metody zmienne są dzielone na części całkowite i ułamkowe .
Nie porównuje liczb zmiennoprzecinkowych z liczbami całkowitymi (bez kropki).
źródło
można użyć awk w połączeniu z warunkiem bash if, awk wypisze 1 lub 0, a te zostaną zinterpretowane przez klauzulę if z wartością true lub false .
źródło
if (( $(echo $d1 $d2 | awk '{if ($1 > $2) print 1;}') )); then echo "yes"; else echo "no"; fi
uważaj podczas porównywania liczb, które są wersjami pakietów, na przykład sprawdzając, czy grep 2.20 jest większy niż wersja 2.6:
Rozwiązałem taki problem z taką funkcją powłoki / awk:
źródło
dpkg --compare-versions
jest często przydatne. Posiada pełną logikę porównywania wbudowanych wersji pakietów Debiana, które są bardziej złożone niż tylkox.y
.Oczywiście, jeśli nie potrzebujesz naprawdę arytmetyki zmiennoprzecinkowej, tylko arytmetyki na np. Wartościach w dolarach, gdzie zawsze są dokładnie dwie cyfry dziesiętne, możesz po prostu upuścić kropkę (skutecznie mnożąc przez 100) i porównać otrzymane liczby całkowite.
To oczywiście wymaga upewnienia się, że obie wartości mają taką samą liczbę miejsc po przecinku.
źródło
Użyłem odpowiedzi stąd i umieściłem je w funkcji, możesz jej użyć w ten sposób:
Po wywołaniu
echo $result
będzie1
w tym przypadku, w przeciwnym razie0
.Funkcja:
Lub wersja z wyjściem debugowania:
Po prostu zapisz funkcję w oddzielnym
.sh
pliku i dołącz ją w następujący sposób:źródło
Publikowałem to jako odpowiedź na https://stackoverflow.com/a/56415379/1745001, kiedy zostało zamknięte jako dupek tego pytania, więc tutaj jest tak, jak ma to zastosowanie również tutaj:
Dla uproszczenia i przejrzystości po prostu użyj awk do obliczeń, ponieważ jest to standardowe narzędzie UNIX, a więc tak samo prawdopodobne, jak bc i znacznie łatwiejsze w obsłudze składniowej.
W przypadku tego pytania:
i dla tego innego pytania, które zostało zamknięte jako dupek tego:
źródło
awk
i takie narzędzia (patrzę na ciebiesed
...) powinny zostać wyrzucone na śmietnik starych projektów, z kodem, którego wszyscy boją się dotykać, ponieważ został napisany w języku, którego nigdy nie czytasz.Lub jesteś stosunkowo rzadkim projektem, który wymaga priorytetu optymalizacji wykorzystania procesora nad optymalizacją konserwacji kodu ... w takim przypadku kontynuuj.
Jeśli nie, to dlaczego nie zamiast tego po prostu użyć czegoś czytelnego i wyraźnego, takiego jak
python
? Twoi koledzy z kodowania i przyszłe ja będą Ci wdzięczni. Możesz używaćpython
inline z bashem, tak jak wszystkich innych.źródło
not(...)
zamiast0 if ... else 1
awk '${print $5}' ptpd_log_file | perl -ne '$_ > 0.000100 && print' > /tmp/outfile
. Bułka z masłem. Każdy język ma swoje miejsce.python -c "import sys; sys.exit(0 if float($num1) < float($num2) else 1)"
jest po prostuawk "BEGIN{exit ($num1 > $num2 ? 0 : 1)}"
.Ten skrypt może pomóc, gdy sprawdzam, czy zainstalowana
grails
wersja jest większa niż wymagane minimum. Mam nadzieję, że to pomoże.źródło
źródło
sprawdź poniższy edytowany kod: -
to działa dobrze.
źródło
Rozwiązanie obsługujące wszystkie możliwe notacje, w tym notację naukową z wykładnikami zarówno dużymi, jak i małymi literami (np.
12.00e4
):źródło
Użyj powłoki Korn, w bashu może być konieczne oddzielne porównanie części dziesiętnej
źródło
Używając bashj ( https://sourceforge.net/projects/bashj/ ), mutanta bash z obsługą java, po prostu piszesz (i JEST łatwy do odczytania):
Oczywiście hybryda bashj bash / java oferuje znacznie więcej ...
źródło
Co powiesz na to? = D
źródło
exit 0
zgłaszać prawdę iexit 1
zwracać fałsz; następnie możesz uprościć do niezwykle eleganckiegoif awk 'BEGIN { exit (ARGV[1] >= ARGV[2]) ? 0 : 1 }' "$VAL_TO_CHECK" 1; then
... (jeszcze bardziej eleganckiego, jeśli umieścisz skrypt Awk w funkcji powłoki).