bash
doesn't natively support a range comparison, nor floating-point numbers, so we have to do some of that ourselves. I'm also going to define a function, and use bc
for floating-point calculation. Here is the end result and test suite:
# 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
The compareRanges
function takes at least two arguments. The first is your t_initial
, and the second is your t_final
. It can take arbitrarily many other arguments in pairs after that, which are your begin1
, fin1
, begin2
, fin2
, in order.
The first test case compares the ranges in the comments on the question: 1-3 and 2-4.
compareRanges 1 3 2 4 && echo BAD || echo OK
So 1
is t_initial
, 3
is t_final
, 2
is begin1
, and 4
is fin1
.
When you want to use multiple ranges, you list them all out in pairs afterwards:
compareRanges 5 7 1 4 2 6 3 9 && echo OK || echo BAD
Here we test against 1-4, 2-6, and 3-9. In the while
loop we look at each pair in turn and compare it against t_initial
and t_final
.
Because bash
doesn't support fractional numbers we use bc
, an arbitrary-precision calculator. Its input is given by the <<<"$t_initial >= $1" ...
part: that feeds the string into standard input. $1
is the start of the range we're currently looking at in this iteration of the loop, and $2
is the end; we compare both the lower and upper bounds at once with &&
. bc
will output 1
when the comparisons are true, and 0
when one is false. We save the result in in_range
, and the function succeeds (return 0
) when both our tests were true.
Fractional numbers can just be specified with their ordinary decimal form:
compareRanges 1.5 2.5 0.3 3.1 && echo OK || echo BAD
bc
will handle numbers with as many fractional digits as you want and with whatever magnitude you need.
At the end, if none of the boundary pairs matched, we fail (return 1
). You can use the function as:
if compareRanges $t_initial $t_final 2 4 11 19
then
...
fi
The test suite should print all "OK" when you run it.
Alternatively, other shells (such as zsh
) do support fractional variable values. If you could run your script in one of those you could avoid the use of bc
, although the comparison is still better off in a function. At least in zsh
's case they are floats, so they're not necessarily accurate; bc
will always be correct.
t_initial=1, t_final=3, begin1=2,fin1=4
? Is that a match or not?begin
andfin
are intended to be the extreme times of a given interval. if the times are not within the intervals, then the condition is not satisfied.t_initial
andt_final
? what is the current output? what is your desired output?