Como posso fazer divisão com variáveis ​​em um shell Linux?

136

Quando executo comandos no meu shell, como abaixo, ele retorna um expr: non-integer argumenterro. Alguém pode explicar isso para mim?

$ x=20
$ y=5
$ expr x / y 
expr: non-integer argument
Julgamento
fonte
4
@ShivanRaptor Embora se possa argumentar que a questão é RTFM, é certamente uma questão válida de programação de shell. Também é uma pergunta razoável para alguém que vem de idiomas que não requerem desreferenciamento (por exemplo, Ruby ou JavaScript). Deve ser deixado aberto.
Todd A. Jacobs
6
@ShivanRaptor Não, isso está no tópico aqui. É sobre programação no Bash. Unix / Linux é principalmente para usar o sistema, não para programação. Agora, os scripts de shell ultrapassam os limites entre programar e usar o sistema, portanto, isso pode estar no tópico de qualquer site. Se houvesse uma pergunta sobre "como faço para configurar a rede", isso definitivamente pertenceria ao Unix / Linux. Se fosse uma pergunta sobre combinações de teclas interativas no Bash, isso também pertenceria a ele. Mas uma pergunta sobre scripts de shell está definitivamente no tópico aqui e ali.
Brian Campbell
Veja minha resposta aqui, que ilustra subtração e divisão de variáveis ​​$ BASH, usando uma chamada para Python do shell (para converter int para flutuar ...): stackoverflow.com/questions/8385627/…
Victoria Stuart

Respostas:

195

Essas variáveis ​​são variáveis ​​de shell. Para expandi-los como parâmetros para outro programa ( ou seja expr ), você precisa usar o $prefixo:

expr $x / $y

A razão pela qual se queixou é porque achou que você estava tentando operar com caracteres alfabéticos ( ou seja, não inteiro)

Se você estiver usando o shell Bash, poderá obter o mesmo resultado usando a sintaxe da expressão:

echo $((x / y))

Ou:

z=$((x / y))
echo $z
arroz
fonte
1
Você pode descobrir muito lendo a página de manual do bash. Digite man bashno prompt ( qpara sair)
paddy
62
Deve-se notar em algum lugar nesta página que a maioria (se não todos) os shells GNU / Linux executam apenas operações inteiras .
Skippy le Grand Gourou
35

Eu acredito que já foi mencionado em outros tópicos:

calc(){ awk "BEGIN { print "$*" }"; }

então você pode simplesmente digitar:

calc 7.5/3.2
  2.34375

No seu caso, será:

x=20; y=3;
calc $x/$y

ou, se preferir, adicione-o como um script separado e disponibilize-o em $ PATH para que você sempre o tenha em seu shell local:

#!/bin/bash
calc(){ awk "BEGIN { print $* }"; }
zielonys
fonte
4
Você também pode usarecho '1 / 3' | bc -l
Eugene
19

Por que não usar let; Acho muito mais fácil. Aqui está um exemplo que você pode achar útil:

start=`date +%s`
# ... do something that takes a while ...
sleep 71

end=`date +%s`
let deltatime=end-start
let hours=deltatime/3600
let minutes=(deltatime/60)%60
let seconds=deltatime%60
printf "Time spent: %d:%02d:%02d\n" $hours $minutes $seconds

Outro exemplo simples - calcule o número de dias desde 1970:

let days=$(date +%s)/86400
Mike Behr
fonte
15

Referenciar variáveis ​​bash requer expansão de parâmetro

O shell padrão na maioria das distribuições Linux é Bash. No Bash, as variáveis ​​devem usar um prefixo de cifrão para a expansão de parâmetros . Por exemplo:

x=20
y=5
expr $x / $y

Obviamente, o Bash também possui operadores aritméticos e uma sintaxe especial de expansão aritmética , portanto, não há necessidade de chamar o binário expr como um processo separado. Você pode deixar o shell fazer todo o trabalho desta maneira:

x=20; y=5
echo $((x / y))
Todd A. Jacobs
fonte
Consulte Expansão aritmética e aritmética de casca no Manual de referência do bash para obter todos os detalhes sangrentos.
Todd A. Jacobs
1
Isto não tem nada a ver com dereferencing mas interpolação e expré desencorajado em 2013.
Gilles Quenot
@sputnick Você está claramente confuso. Por favor, sinta-se livre para consultar um dicionário. Veja desreferência e interpole .
Todd A. Jacobs
1
Uma palavra melhor está se expandindo , mas não desreferenciando . a desreferenciação é usada quando usamos ponteiros , não é o caso aqui, são apenas variáveis ​​simples.
Gilles Quenot
1
@ Pashant: tldp não é conhecido por ser uma boa referência no mundo do bash.
Gilles Quenot
1

vamos supor

x=50
y=5

então

z=$((x/y))

isso funcionará corretamente. Mas se você quiser usar / operator nas instruções de caso, ele não poderá resolvê-lo. entre com o código aqui Nesse caso, use strings simples como div ou devide ou qualquer outra coisa. Veja o código

Pooja Rajput
fonte
Isto está errado. /funciona bem como um rótulo de caixa de concha. O que não funciona é usar *para multiplicar sem citá-lo, o que pode ser o que você realmente fez; que faz com que ele efetivamente substitua todos os itens a seguir no caso, que no seu exemplo é 'devide' e 'modulo'
dave_thompson_085
0

Para obter os números após o ponto decimal, você pode fazer o seguinte: -

read num1 num2
div=`echo $num1 / $num2 |bc -l`
echo $div
Shayan Chatterjee
fonte