como posso adicionar (subtrair, etc.) dois números com o bash?

90

Eu posso ler os números e a operação com:

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

mas todas as minhas tentativas de adicionar os números falham:

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

Corre:

First number please
1
Second mumber please
2
Operation?
+

Resultado:

num1+num2

...ou...

echo $num1+$num2;;

# results in: 1+2    

...ou...

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

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

Parece que ainda estou conseguindo seqüências de caracteres quando tento add add ("2 + 2" em vez de "4").

Michael Durrant
fonte
5
Editei o título porque essa é uma boa pergunta geral e, se você restringisse o contexto, teria percebido que isso não tem nada a ver com casenada além de uma linha: echo $num+$numpois isso reproduzirá exatamente o problema . A idéia com minimizando contexto em questões de programação é explicado aqui: sscce.org
goldilocks
2
+1 Olá goldilocks, sim, isso ficou claro para mim depois, mas sim, eu concordo totalmente com sua linha de raciocínio e sim, quanto mais específica e 'singular' uma pergunta for, melhor. Congratulo-me com a sua edição (s) :) Obrigado :)
Michael Durrant

Respostas:

117

A aritmética nos shells POSIX é feita com $e parênteses duplos (( )):

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

Você pode atribuir a partir disso (sans echo):

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

Há também expr:

expr $num1 + $num2

$(())É preferível usar scripts, pois evita uma bifurcação / execução para o exprcomando.

Cachinhos Dourados
fonte
Ou mesmo diretamente, echo $(($num1$op$num2))sem envolver case.
manatwork
Não há nenhum caseenvolvido aqui.
GOLDILOCKS
1
Não, mas você usou literal +, portanto precisará do caseexterior para lidar com a subtração separadamente.
manatwork
1
@manatwork: Você quer eliminar o casecódigo do OP com echo $(($num1$op$num2))- isso funcionará, mas usar o caseé mais robusto, pois você pode lidar com erros com um padrão *.
GOLDILOCKS
+1 para vocês dois. Eu estava usando o case (talvez não o tenha mostrado no início), mas como vocês dois perceberam que o problema não era sobre o caso.
Michael Durrant
13

A resposta existente é o bash puro, portanto será mais rápido que isso, mas só pode lidar com números inteiros. Se você precisar lidar com carros alegóricos, precisará usar o programa externo bc.

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

O scale=4diz bcpara usar quatro casas decimais. Veja man bcpara mais informações.

evilsoup
fonte
Observe que, embora bashnão suporta aritmética de ponto flutuante com $((...)), muitas conchas ( ksh93, zsh, yashpelo menos) fazer. A vantagem bcé que ele suporta precisão arbitrária, enquanto a aritmética de shell é limitada ao doubletipo de processador . Observe que você não precisa definir scaleaqui. Para adições, o scaleparâmetro não é usado. A escala de 3.1415+9.99será derivada da dos operandos (aqui 4).
Stéphane Chazelas
Como fazer as contas se um valor é 450e o outro é decimal armazenado em uma variável $mynumber? Por exemplo 450-$mynumber,.
Sigur
@sigur echo "450-$mynumber" | bcdeve fazê-lo. Se você deseja expandir uma variável, use aspas duplas em vez de aspas simples.
evilsoup
@evilsoup, agora funciona como um encanto. Obrigado.
Sigur
computedval=$(echo 'scale=10;var1-var2' | bc)não funciona, nem funcionacomputedval=$(echo 'scale=10;$var1-$var2' | bc)
StatsSorceress
5
echo `expr $a + $b`   
echo `expr $a - $b`   
echo `expr $a \* $b`   
echo `expr $a / $b`   

Observe que \antes de *(para multiplicação), toda a expressão deve estar entre aspas `.

Himani
fonte
1
exprnão é necessário e nunca é necessário capturar a saída padrão de um comando apenas para gravá-lo novamente na saída padrão.
Chepner #
2

minimalista

total=0
((total+=qty))
geekzspot
fonte
1

Você também pode usar a $[ ... ]estrutura. Nesse caso, usamos o mecanismo incorporado no Bash, que é mais rápido e um pouco mais conveniente de usar. Como sabemos que tudo entre $ [e] é tratado como uma expressão, não precisamos preceder as variáveis ​​com $. Da mesma forma, não precisamos nos proteger *de tratá-lo como um padrão.

num1=2
num2=3
echo $[num1 + num2]
5
jedi
fonte
0

Com base na sequência de entradas solicitadas ao usuário, parece que você está usando a notação de polimento reverso.

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

Você pode fazer melhor apenas usando dc(calculadora de mesa) diretamente, pois é para isso que serve.

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

Exemplo de sessão usando dc:

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

Ou, de maneira não interativa:

$ dc -e '1 2 + p'
3
$
Curinga
fonte