jak mogę dodać (odjąć itp.) dwie liczby za pomocą bash?

90

Potrafię odczytać liczby i operacje za pomocą:

echo "First number please"
read num1
echo "Second number please"
read num2
echo "Operation?"
read op

ale potem wszystkie moje próby dodania liczb kończą się niepowodzeniem:

case "$op" in
  "+")
    echo num1+num2;;
  "-")
    echo `num1-num2`;;
esac

Biegać:

First number please
1
Second mumber please
2
Operation?
+

Wynik:

num1+num2

...lub...

echo $num1+$num2;;

# results in: 1+2    

...lub...

echo `$num1`+`$num2`;;

# results in: ...line 9: 1: command not found

Wygląda na to, że wciąż otrzymuję ciągi znaków, gdy próbuję dodać add („2 + 2” zamiast „4”).

Michael Durrant
źródło
5
Zredagowałem twój tytuł, ponieważ jest to dobre pytanie ogólne, a jeśli zawęzisz kontekst, zdasz sobie sprawę, że nie ma to nic wspólnego caseani nic poza jedną linią: echo $num+$numponieważ to dokładnie odtworzy problem . Pomysł zminimalizowania kontekstu w pytaniach programowych wyjaśniono tutaj: sscce.org
goldilocks
2
+1 Cześć złotowłosa, tak, to stało się dla mnie jasne, ale tak, całkowicie zgadzam się z twoim tokiem rozumowania i tak, im bardziej szczegółowe i „pojedyncze” pytanie jest lepsze. Cieszę się z twoich edycji :) Dziękuję :)
Michael Durrant

Odpowiedzi:

116

Arytmetyka w powłokach POSIX odbywa się za pomocą $podwójnych nawiasów (( )):

echo "$(($num1+$num2))"

Możesz przypisać z tego (sans echo):

num1="$(($num1+$num2))"

Istnieje również expr:

expr $num1 + $num2

W skryptowaniu $(())preferowane jest unikanie rozwidlenia / wykonania exprpolecenia.

Złotowłosa
źródło
Lub nawet bezpośrednio, echo $(($num1$op$num2))bez angażowania case.
manatwork
Nie ma casetu mowy o zaangażowaniu.
goldilocks
1
Nie, ale użyłeś literału +, więc będziesz potrzebował casezewnętrznej strony do oddzielnego odejmowania.
manatwork 30.09.13
1
@manatwork: Masz na myśli wyeliminowanie casez kodu PO za pomocą echo $(($num1$op$num2))- to zadziała, ale użycie casejest bardziej niezawodne, ponieważ domyślnie możesz obsługiwać błędy *.
goldilocks 30.09.13
+1 dla was obu. Używałem przypadku (być może nie pokazałem go na początku), ale ponieważ oboje zdaliście sobie sprawę, że problem nie dotyczył przypadku.
Michael Durrant
13

Istniejąca odpowiedź to czysty bash, więc będzie szybszy niż ten, ale może obsłużyć tylko liczby całkowite. Jeśli potrzebujesz obsługi pływaków, musisz użyć zewnętrznego programu bc.

$ echo 'scale=4;3.1415+9.99' | bc
13.1315

scale=4Mówi bcużyć czterech miejsc po przecinku. Zobacz man bcwięcej informacji.

zła
źródło
Należy zauważyć, że bashnie obsługuje pływających arytmetyki punkt o $((...)), wiele muszli ( ksh93, zsh, yashprzynajmniej) zrobić. Zaletą bcjest to, że obsługuje dowolną precyzję, podczas gdy arytmetyka powłoki jest ograniczona do typu procesora double. Pamiętaj, że nie musisz scaletutaj ustawiać . W przypadku dodatków scaleparametr nie jest używany. Skala 3.1415+9.99będzie pochodzić od skali operandów (tutaj 4).
Stéphane Chazelas,
Jak wykonać matematykę, jeśli jedna wartość jest, 450a druga dziesiętna jest przechowywana w zmiennej $mynumber? Na przykład 450-$mynumber.
Sigur,
@sigur echo "450-$mynumber" | bcpowinien to zrobić. Jeśli chcesz, aby zmienna się rozwijała, musisz użyć podwójnych cudzysłowów zamiast pojedynczych cudzysłowów.
evilsoup
@evilsoup, teraz działa jak urok. Dzięki.
Sigur,
computedval=$(echo 'scale=10;var1-var2' | bc)nie działa, ani nie działacomputedval=$(echo 'scale=10;$var1-$var2' | bc)
StatsSorceress
5
echo `expr $a + $b`   
echo `expr $a - $b`   
echo `expr $a \* $b`   
echo `expr $a / $b`   

Zauważ, że \przed *(dla mnożenia) całe wyrażenie musi znajdować się w cudzysłowach `.

Himani
źródło
1
exprnie jest konieczne i nigdy nie jest konieczne przechwytywanie standardowego wyjścia polecenia tylko po to, aby zapisać go z powrotem na standardowe wyjście.
chepner
2

minimalistyczny

total=0
((total+=qty))
geekzspot
źródło
1

Możesz także użyć $[ ... ]struktury. W tym przypadku korzystamy z wbudowanego mechanizmu w Bash, który jest szybszy i nieco wygodniejszy w użyciu. Ponieważ wiemy, że wszystko pomiędzy $ [, a] jest traktowane jako wyrażenie, nie musimy poprzedzać zmiennych $. Podobnie nie musimy zabezpieczyć się *przed traktowaniem go jak wzoru.

num1=2
num2=3
echo $[num1 + num2]
5
jedi
źródło
0

W oparciu o sekwencję danych wejściowych, których żądasz od użytkownika, wydaje się, że używasz odwrotnej notacji polskiej.

echo "First number please"
read num1
echo "Second number please"
read num2
echo "Operation?"
read op

Lepiej jest użyć bezpośrednio dc(kalkulatora biurkowego), ponieważ po to jest.

DESCRIPTION
       Dc is a reverse-polish desk calculator which supports unlimited pre-
       cision arithmetic.

Przykładowa sesja z wykorzystaniem dc:

$ dc
1 2 + p    # This part is typed; the result comes next.
3
q  # This is also typed.
$

Lub nieinteraktywnie:

$ dc -e '1 2 + p'
3
$
Dzika karta
źródło