Fazendo matemática simples na linha de comando usando funções bash: $ 1 dividido por $ 2 (talvez usando bc)

33

Às vezes, preciso dividir um número por outro. Seria ótimo se eu pudesse definir uma função bash para isso. Até agora, sou forçado a usar expressões como

echo 'scale=25;65320/670' | bc

mas seria ótimo se eu pudesse definir uma função .bashrc que parecia

divide () {
  bc -d $1 / $2
}
ixtmixilix
fonte

Respostas:

45

Eu tenho uma função útil do bash chamada calc:

calc () {
    bc -l <<< "$@"
}

Exemplo de uso:

$ calc 65320/670
97.49253731343283582089

$ calc 65320*670
43764400

Você pode mudar isso para se adequar. Por exemplo:

divide() {
    bc -l <<< "$1/$2"
}

Nota: <<< é uma string here que é alimentada no stdin de bc. Você não precisa invocar echo.

dogbane
fonte
3
Concordo que está melhor sem o eco adicional, mas, como é um shell embutido, ele vem com pouco ou nenhum custo adicional. O que me impede de usar '<<<' nas funções de shell é sua limitação ao bash, enquanto o eco adicional permite usá-lo no shell bourne original ou no ksh sem alterações.
Tatjana Heuser 31/01
@TatjanaHeuser ksh, a variante 93, suporta as strings aqui.
Kusalananda
Para atribuir a uma variável, eu fiz isso: foo = $ (bc -l <<< "(2 * 5) + 5")
thebiggestlebowski
20

O Bash pode fazer as próprias contas em certa medida. Não é útil para precisão, no entanto, à medida que arredonda.

[user]$ echo $(( 10/5 ))
2

Mas você está exatamente certo - uma função bash seria um atalho simples e seu exemplo basicamente funciona.

divide() {
  echo "scale=25;$1/$2" | bc
}

Jogue isso no seu .bashrc e então você pode:

[user]$ divide 10 5
2.0000000000000000000000000
rjewell
fonte
1
echo $((10 / 5))não precisa de cotação.
usuário desconhecido
1
Aborrecimento significativo: echo $((6383/7671)) dará zero. Você precisa ser explícito sobre os números de ponto flutuante:echo $((6383.0/7671.0))
Sridhar Sarnobat
9

Você provavelmente conhece o bash 'expr' como em

$ expr 60 / 5
12

que é limitado a números inteiros e precisa dos espaços entre os argumentos.

O que impede você de definir uma função nas linhas da expressão de eco que você já está usando? Ou seja,

 divide () {
   echo $1/$2 | bc
 }
Tatjana Heuser
fonte
1
apenas ignorância. Eu não sabia que eu poderia fazê-lo funcionar dessa maneira ...
ixtmixilix
7

Não é realmente uma resposta para essa pergunta precisa, mas pode ser bom saber. Use zsh;-)

% echo $((65320./670))
97.492537313432834
Stéphane Gimenez
fonte
Eu estava realmente procurando por esta pergunta, porque eu mudei para zsh e não poderia usar da festa exprembutido, então boa resposta independentemente :)
Steen Schütt
2

Se você calcinstalou no seu sistema e não gosta de arredondamentos, pode:

div() { calc "$1 / $2"; }

fonte
hmm ... não foi possível encontrar nenhum pacote debian para 'calc'
ixtmixilix 31/01
O pacote é chamado apcalc (Precisão Arbitária) ... O binário é chamadocalc
Peter.O
@ Peter.O Ok, nos repositórios do Arch Linux é chamado calc.
2

Um truque sujo para valores pequenos e uma precisão limitada sem o uso de bc seria, multiplicar o nomeador antes da divisão, para obter um resultado preciso.

Exemplo sem precisão:

echo $((13/7)) 
1

e com precisão de 2 dígitos: multiplique por 100 e mova o ponto decimal 2 etapas para a esquerda:

echo $((100*13/7)) | sed 's/..$/.&/'
1.85
echo $((100*13/7))%
185%

Isso só é útil se o intervalo de números for conhecido antes e a precisão for sempre a mesma. Evitar chamar bc e chamar sed não parece muito razoável.

Observe que multiplicar os valores pode levar a erros de estouro, mas não muito cedo:

echo $((1000000000*12345678901))
-6101065172709551616
Usuário desconhecido
fonte
O uso de parênteses duplos para avaliar expressões matemáticas foi preterido. Uso: $[expression]em vez
laebshade
3
@laebshade: Eu posso provar que você está errado, o oposto é verdadeiro. Aqui está uma citação do manual do bash:The old format $[expression] is deprecated and will be removed in upcoming versions of bash.
user unknown
Também discutido aqui ,  aqui  e  aqui .
G-Man diz 'Restabelecer Monica'
0

Em vez de usar o bc, você pode usar o awk:

div() { awk -v p=$1 -v q=$2 'BEGIN{print p/q}'; }
jfg956
fonte
-4
echo Division
efgh=$num1/$num2
remainder=$num1%num2
echo $num1 "/" $num2 "=" $efgh.$remainder
echo
Boomer
fonte