user3055262
user3055262

Reputation: 405

Undesired result if condition

Below is the file on which I am applying the below unix script.

    0.30 2.30 - - - - - - -
    2.30 3.30 - - NA NA - - -
    3.30 4.30 - - NA NA - - -
    4.30 5.30 - - - - - - -
    5.30 6.30 - - NA NA - - -
    6.30 0.30 - - - - - - -

##Time=`echo $(date) | awk -F ' ' '{print $4}' | awk -F ':' '{print $1}'` 
Time=05;
Result="False";
while [[ "${Result}" != "True" ]]
do
    while read -r f1 f2 f3 f4 f5 f6 f7 f8 f9
    do
        if [[ "${Time}" -ge "${f1}" && "${Time}" -le "${f2}" ]]
        then 
                echo $Time is between $f1 $f2 True
                Result="True";
        else
                echo $Time is between $f1 $f2 False
        fi
    done < consolidated.txt
done

I am getting the below result: Please notice that the if condition is being satisfied twice. 05 is not between 5.30 and 6.30 still it returns true. What am I missing here.

05 is between 0.30 2.30 False
05 is between 2.30 3.30 False
05 is between 3.30 4.30 False
05 is between 4.30 5.30 True
05 is between 5.30 6.30 True
05 is between 6.30 0.30 False

Upvotes: 0

Views: 39

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 754280

Various issues are visible:

  • The outer loop in your code is problematic. If none of the time ranges in consolidated.txt matches, ${Result} remains False and the outer loop never terminates.
  • The last time range in the data, 6.30 0.30 is never going to match anything because the end of the range is smaller numerically than the start of the range.
  • With your condition using time >= start && time <= end, if the time value is 5.30 then that is going to match both the 4.30 5.30 range (it is equal to the end time) and the 5.30 6.30 range (it is equal to the start time).

Unlike Bash, Korn shell does support floating point arithmetic, which is useful.

Instead of the [[ … ]] and using string comparisons (-ge, -le), you should use (( … )) and (floating point) numeric comparisons (>=, <).

Assembling these changes into a single script, and ignoring the Result variable since it isn't relevant here, you get:

#!/bin/ksh

for Time in 0 3 05 5.30 7.00
do
    while read -r f1 f2 f3 f4 f5 f6 f7 f8 f9
    do
        if (( "${Time}" >= "${f1}" && "${Time}" < "${f2}" ))
        then echo "${Time} is between ${f1} and ${f2} True"
        else echo "${Time} is between ${f1} and ${f2} False"
        fi
    done << EOF
    0.30 2.30 - - - - - - -
    2.30 3.30 - - NA NA - - -
    3.30 4.30 - - NA NA - - -
    4.30 5.30 - - - - - - -
    5.30 6.30 - - NA NA - - -
    6.30 24.00 - - - - - - -
EOF
done

Yes, the EOF at the end of the here document does need to be in the left margin. You could use <<-'EOF' and indent the end marker EOF as long as the indentation is tabs, not blanks.

The output from this script is:

0 is between 0.30 and 2.30 False
0 is between 2.30 and 3.30 False
0 is between 3.30 and 4.30 False
0 is between 4.30 and 5.30 False
0 is between 5.30 and 6.30 False
0 is between 6.30 and 24.00 False
3 is between 0.30 and 2.30 False
3 is between 2.30 and 3.30 True
3 is between 3.30 and 4.30 False
3 is between 4.30 and 5.30 False
3 is between 5.30 and 6.30 False
3 is between 6.30 and 24.00 False
05 is between 0.30 and 2.30 False
05 is between 2.30 and 3.30 False
05 is between 3.30 and 4.30 False
05 is between 4.30 and 5.30 True
05 is between 5.30 and 6.30 False
05 is between 6.30 and 24.00 False
5.30 is between 0.30 and 2.30 False
5.30 is between 2.30 and 3.30 False
5.30 is between 3.30 and 4.30 False
5.30 is between 4.30 and 5.30 False
5.30 is between 5.30 and 6.30 True
5.30 is between 6.30 and 24.00 False
7.00 is between 0.30 and 2.30 False
7.00 is between 2.30 and 3.30 False
7.00 is between 3.30 and 4.30 False
7.00 is between 4.30 and 5.30 False
7.00 is between 5.30 and 6.30 False
7.00 is between 6.30 and 24.00 True

If you change the < condition to <=, which is equivalent to what the question uses, then you get the output:

…
5.30 is between 3.30 and 4.30 False
5.30 is between 4.30 and 5.30 True
5.30 is between 5.30 and 6.30 True
5.30 is between 6.30 and 24.00 False
…

With the last range left as 6.30 0.30, the final part of the output would look like:

…
7.00 is between 5.30 and 6.30 False
7.00 is between 6.30 and 0.30 False

Upvotes: 1

Niall Cosgrove
Niall Cosgrove

Reputation: 1303

The problem you are having is due to the line Time=05; ksh is not interpreting this as a floating point value. let will force it to do so.

$ Time=05;echo $Time
05
$ let Time=05;echo $Time
5

Another common idiom is Time=$(echo $Time |bc)

Here is an alternative phrasing for your logic:

$echo $Time $f1 $f2
05 5.30 6.30
$
$let Time=05     
$ if [[ (( $Time > $f1 )) && (( $Time < $f2 )) ]]
> then 
>        echo $Time is between $f1 $f2 True
> else
>        echo $Time is between $f1 $f2 False
>fi    
5 is between 5.30 6.30 False

The (( ... )) is a numeric conditional similar to [[ ... ]]
It is designed for use in if and while constructs.

You can find more details here in section 6.2.2 of Learning the Korn Shell.

Upvotes: 1

Related Questions