bash
não suporta nativamente uma comparação de intervalo, nem números de ponto flutuante, por isso temos que fazer alguns de nós mesmos. Eu também vou definir uma função e usar bc
para o cálculo de ponto flutuante. Aqui está o resultado final e a suíte de testes:
# Call as 'compareRanges start end b1 f1 b2 f2 b3 f3...'
compareRanges() {
local t_initial=$1
local t_final=$2
shift 2
while [ ${#@} -gt 1 ]
do
local in_range=$(bc <<<"$t_initial >= $1 && $t_final <= $2")
if [ $in_range = 1 ]
then
# Debugging output to stderr - can be removed:
echo "[$t_initial,$t_final] is within [$1,$2]" >&2
return 0
fi
shift 2
done
# Debugging output to stderr - can be removed:
echo "[$t_initial,$t_final] is not within any ranges." >&2
return 1
}
# Basic integers from the example
compareRanges 1 3 2 4 && echo BAD || echo OK
compareRanges 1 3 1 3 && echo OK || echo BAD
compareRanges 1 3 0 4 && echo OK || echo BAD
# Fractional numbers
compareRanges 1.5 2.5 1.1 2.2 && echo BAD || echo OK
compareRanges 1.5 2.5 0.3 3.1 && echo OK || echo BAD
# Multiple ranges
compareRanges 5 7 1 4 2 6 3 9 && echo OK || echo BAD
compareRanges 5 7 1 2 3 4 5 6 7 8 && echo BAD || echo OK
A função compareRanges
leva pelo menos dois argumentos. O primeiro é seu t_initial
e o segundo é seu t_final
. Pode levar arbitrariamente muitos outros argumentos em pares depois disso, que são seus begin1
, fin1
, begin2
, fin2
, em ordem.
O primeiro caso de teste compara os intervalos nos comentários sobre a questão: 1-3 e 2-4.
compareRanges 1 3 2 4 && echo BAD || echo OK
Portanto, 1
é t_initial
, 3
é t_final
, 2
é begin1
e 4
é fin1
.
Quando você quiser usar vários intervalos, liste-os em pares depois:
compareRanges 5 7 1 4 2 6 3 9 && echo OK || echo BAD
Aqui testamos contra 1-4, 2-6 e 3-9. No loop while
, olhamos cada par e comparamos com t_initial
e t_final
.
Como bash
não suporta números fracionários, usamos bc
, uma calculadora de precisão arbitrária . Sua entrada é dada pela <<<"$t_initial >= $1" ...
part: que alimenta a string na entrada padrão. $1
é o começo do intervalo que estamos vendo nesta iteração do loop, e $2
é o fim; Comparamos os limites inferior e superior ao mesmo tempo com &&
. bc
produzirá 1
quando as comparações forem verdadeiras e 0
quando uma for falsa. Nós salvamos o resultado em in_range
e a função é bem-sucedida ( return 0
) quando os dois testes são verdadeiros.
Os números fracionários podem ser especificados apenas com a sua forma decimal comum:
compareRanges 1.5 2.5 0.3 3.1 && echo OK || echo BAD
bc
lidará com números com quantos dígitos fracionários você quiser e com a magnitude que precisar.
No final, se nenhum dos pares limite corresponder, nós falhamos ( return 1
). Você pode usar a função como:
if compareRanges $t_initial $t_final 2 4 11 19
then
...
fi
O conjunto de testes deve imprimir todos os "OK" quando você executá-lo.
Como alternativa, outros shells (como zsh
) do suportam valores de variáveis fracionárias. Se você pudesse executar seu script em um desses, você poderia evitar o uso de bc
, embora a comparação ainda seja melhor em uma função. Pelo menos no caso de zsh
eles são floats, então eles não são necessariamente precisos; bc
estará sempre correto.