Estou tentando comparar dois números de ponto flutuante em um script bash. Eu tenho que variáveis, por exemplo
let num1=3.17648e-22
let num2=1.5
Agora, eu só quero fazer uma comparação simples desses dois números:
st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
Infelizmente, tenho alguns problemas com o tratamento correto do num1, que pode ser do "formato eletrônico". :(
Qualquer ajuda, dicas são bem-vindas!
bash
floating-point
comparison
numbers
Jonas
fonte
fonte
Respostas:
Mais convenientemente
Isso pode ser feito de maneira mais conveniente usando o contexto numérico do Bash:
Explicação
A tubulação através do comando básico da calculadora
bc
retorna 1 ou 0.A opção
-l
é equivalente a--mathlib
; carrega a biblioteca matemática padrão.Colocar a expressão inteira entre parênteses duplos
(( ))
converterá esses valores em respectivamente verdadeiro ou falso.Por favor, verifique se o
bc
pacote básico da calculadora está instalado.Isso também funciona para carros alegóricos em formato científico, desde que uma letra maiúscula
E
seja empregada, por exemplonum1=3.44E6
fonte
bc
pacote da calculadora instalado.0: not found
com a declaraçãoif (( $(echo "$TOP_PROCESS_PERCENTAGE > $THRESHOLD" | bc -l) )); then
.bc
backticks nos backticks ou$()
então em(( ))
... ie(( $(bc -l<<<"$a>$b") ))
e não(( bc -l<<<"$a>$b" ))
.E
e todos os erros de sintaxe desaparecerão.O bash lida apenas com números inteiros, mas você pode usar o
bc
comando da seguinte maneira:Observe que o sinal do expoente deve estar em maiúsculas
fonte
bc
ferramenta e é isso que eu recomendaria a qualquer programador BASH. BASH é uma linguagem sem letra. Sim, ele pode fazer aritmética inteira, mas para ponto flutuante você deve usar alguma ferramenta externa. BC é o melhor, porque é para isso que é feito.É melhor usar
awk
para matemática não inteira. Você pode usar esta função do utilitário bash:E chame-o como:
fonte
awk
ebc
em scripts de shell é uma prática padrão desde os tempos antigos, eu diria que alguns recursos nunca foram adicionados aos shells porque estão disponíveis no awk, bc e outras ferramentas Unix. Não há necessidade de pureza em scripts de shell.exit
que o Awk comunique o resultado de volta ao shell de maneira adequada e legível por máquina.if awk -v n1="123.456" -v n2="3.14159e17" 'BEGIN { exit (n1 <= n2) }' /dev/null; then echo bigger; else echo not; fi
... embora observe como a condição é invertida (o status de saída 0 significa sucesso para o shell).python
. Vocêperl
instalado por padrão em muitos sistemas Linux / Unix .. mesmophp
tambémawk
solução é mais robusta no meu caso do que abc
que retorna resultados errados por um motivo que não obtive.Solução de bash pura para comparar flutuadores sem notação exponencial, zeros à esquerda ou à direita:
A ordem dos operadores lógicos é importante . Partes inteiras são comparadas como números e partes fracionárias são intencionalmente comparadas como seqüências de caracteres. As variáveis são divididas em partes inteiras e fracionárias usando este método .
Não compara flutuações com números inteiros (sem ponto).
fonte
você pode usar o awk combinado com uma condição bash if, o awk imprimirá 1 ou 0 e esses serão interpretados pela cláusula if com true ou false .
fonte
if (( $(echo $d1 $d2 | awk '{if ($1 > $2) print 1;}') )); then echo "yes"; else echo "no"; fi
tenha cuidado ao comparar números que são versões de pacotes, como verificar se o grep 2.20 é maior que a versão 2.6:
Eu resolvi esse problema com essa função shell / awk:
fonte
dpkg --compare-versions
geralmente é útil. Ele tem a lógica completa para comparar as versões dos pacotes Debian embutidas nele, que são mais complexas do que justasx.y
.Obviamente, se você não precisa realmente de aritmética de ponto flutuante, apenas aritmética em, por exemplo, valores em dólares, onde sempre há exatamente dois dígitos decimais, você pode simplesmente soltar o ponto (multiplicando efetivamente por 100) e comparar os números inteiros resultantes.
Obviamente, isso exige que você tenha certeza de que ambos os valores tenham o mesmo número de casas decimais.
fonte
Eu usei as respostas daqui e as coloquei em uma função, você pode usá-las assim:
Uma vez chamado,
echo $result
será1
neste caso, caso contrário0
.A função:
Ou uma versão com saída de depuração:
Apenas salve a função em um
.sh
arquivo separado e inclua-a assim:fonte
Eu estava postando isso como uma resposta para https://stackoverflow.com/a/56415379/1745001 quando ele foi fechado como um dup dessa pergunta, então aqui está como se aplica aqui também:
Para simplicidade e clareza, basta usar o awk para os cálculos, pois é uma ferramenta UNIX padrão e com a mesma probabilidade de estar presente como bc e muito mais fácil trabalhar sintaticamente.
Para esta pergunta:
e para essa outra pergunta que foi encerrada como um dup desta:
fonte
awk
e ferramentas como essa (estou olhando para vocêsed
...) devem ser relegadas para o caixote do lixo de projetos antigos, com um código que todo mundo tem medo de tocar desde que foi escrito em um idioma de leitura nunca.Ou você é um projeto relativamente raro que precisa priorizar a otimização do uso da CPU em vez da otimização da manutenção do código ... nesse caso, continue.
Caso contrário, por que não usar apenas algo legível e explícito, como
python
? Seus colegas programadores e o seu futuro serão agradecidos. Você pode usarpython
inline com bash como todos os outros.fonte
not(...)
, em vez de0 if ... else 1
awk '${print $5}' ptpd_log_file | perl -ne '$_ > 0.000100 && print' > /tmp/outfile
. Mole-mole. Toda língua tem seu lugar.python -c "import sys; sys.exit(0 if float($num1) < float($num2) else 1)"
é simplesmenteawk "BEGIN{exit ($num1 > $num2 ? 0 : 1)}"
.Esse script pode ajudar onde estou verificando se a
grails
versão instalada é maior que o mínimo necessário. Espero que ajude.fonte
fonte
verifique o código editado abaixo: -
isso funciona bem.
fonte
Uma solução que suporta todas as notações possíveis, incluindo a notação científica com expoentes em maiúsculas e minúsculas (por exemplo,
12.00e4
):fonte
Use o shell korn, no bash você pode precisar comparar a parte decimal separadamente
fonte
Usando o bashj ( https://sourceforge.net/projects/bashj/ ), um mutante do bash com suporte a java, basta escrever (e é fácil de ler):
Obviamente, a hibridação bashj bash / java oferece muito mais ...
fonte
Que tal agora? = D
fonte
exit 0
relatar a verdade eexit 1
retornar falso; então você pode simplificar para o extraordinariamente eleganteif awk 'BEGIN { exit (ARGV[1] >= ARGV[2]) ? 0 : 1 }' "$VAL_TO_CHECK" 1; then
... (mais elegante ainda se você encapsular o script Awk em uma função shell).