Если условие с 2 различными значениями в определенном диапазоне (граница)

Скажем, у меня есть координата (x, y), я хочу сделать две категории: хороший или плохой.

Я понятия не имею, как выразить его словами или ключевые слова, таким образом, я создал пример того, что я хочу.

Я создал сценарий удара как это:

x=3.5 #(example)
y=-2.5 #(example)
if [ $x -ge 0.1 -a $x -le 5.5 ] && [ $y -ge -5.9 -a $y -le -0.1 ]; then cat="good";
elif [ $x -ge 5.5 -a $x -le 10.5 ] && [ $y -ge -10.9 -a $y -le -5.9 ]; then cat="bad";
fi
echo "$cat"

На том сценарии я хочу знать, ли x в диапазоне 0.1, пока 5.5 (0.1 <x <5.5) и y в-5.9 до-0.1 (-5.9 <y <-0.1) не верны затем, что он дает результат как good. С различными границами это должно дать a bad результат.

Я выполнил его, и это дает результат как ожидаемое целое выражение.

Когда я пытаюсь заменить оператор -ge (или -le) с оператором > (или <), или попытка добавить квадратную скобку и что-либо, о чем я мог думать, это дает ту же ошибку, или никакие результаты не даны.

Как я должен приблизиться к этому?

1
задан 23 June 2018 в 23:02

2 ответа

Bash может только сделать целочисленную математику. Если значения имеют постоянное число десятичных разрядов, можно удалить . (использование sed или awk или любая команда Вам нравится), и сравните получающиеся значения. Например, если у них есть точно один десятичный разряд как 10.0, 0.4, 2.2, удаление . умножит их на десять, приводя к 100, 04, 22 (использование старой тестовой команды [, продвижение 0s не имеют значения для целочисленного сравнения). Необходимо будет умножить границы соответственно, конечно.

С другой стороны, можно использовать bc, который будет работать с числами с плавающей точкой произвольной точности. bc чтения stdin, таким образом, можно, например, повторить выражение и передать его по каналу к bc следующим образом:

echo "$x>=0.1 && $x<=5.5" | bc

Вывод будет 1 если выражение true, 0 иначе. Прочитайте руководство (человек до н.э), если Вы хотите узнать больше о его синтаксисе.

Для слияния этого в сценарий можно использовать замену команды как это:

if [ $(echo "$x>=0.1 && $x<=5.5" | bc) -eq 1 ] ; then cat="good";

Обратите внимание, что мы все еще должны проверить если bc вывод команды 1, потому что [ 0 ] также оценит к true.

Наконец, Ваше использование в качестве примера bc:

x=6.5 #(example)
y=-7.5 #(example)
if [ $(echo "$x>=0.1 && $x<=5.5 && $y>=-5.9 && $y<=-0.1" | bc) -eq 1 ] ; then cat="good";
elif [ $(echo "$x>=5.5 && $x<=10.5 && $y>=-10.9 && $y<=-5.9" | bc) -eq 1 ]; then cat="bad";
fi
echo "$cat"

Начиная с наличия тех едва читаемых строк в скобках делает это более подверженным ошибкам, можно использовать функции удара и переменные как в следующем примере. Это может быть полезно, если Вы хотите добавить дополнительный elif пункты с различными диапазонами. (Благодаря wjandrea для полезных подсказок)

x=6.5 #(example)
y=-6.5 #(example)

boundsGood="0.1 5.5 -5.9 -0.1"
boundsBad="5.5 10.5 -10.9 -5.9"

# Paramaters in following order: x, y, xmin, xmax, ymin, ymax; bounds are inclusive.
function in_bounds {
    local x=$1
    local y=$2
    local x_min=$3
    local x_max=$4
    local y_min=$5
    local y_max=$6
    [ $(echo "$x >= $x_min && $x <= $x_max && $y >= $y_min && $y <= $y_max" | bc) -eq 1 ]
}

if in_bounds $x $y $boundsGood ; then cat="good";
elif in_bounds $x $y $boundsBad ; then cat="bad";
fi
echo "$cat"

Альтернативная версия in_bounds функциональное использование printf (благодаря steeldriver):

# Paramaters in following order: x, y, xmin, xmax, ymin, ymax; bounds are inclusive.
function in_bounds {
    [ $(printf "x = %f; y = %f; xmin = %f; xmax = %f; ymin = %f; ymax = %f; x >= xmin && x <= xmax && y >= ymin && y <= ymax\n" "$1" "$2" "$3" "$4" "$5" "$6" | bc) -eq 1 ]
}
4
ответ дан 3 December 2019 в 06:29

Если абсолютно необходимо оставаться в сценарии оболочки - добавьте переменные во встроенный сценарий awk, чтобы передать значения x и y в среду awk, и используйте ENVIRON["variable_name"] для доступа к ним; и пусть он выполняет работу по печати необходимых вам строк (или заключает весь сценарий в $(...), чтобы сохранить вывод).

Если в этом нет необходимости, покончите с частью сценария оболочки и просто оставьте awk в покое.

#!/bin/sh

x=3.5
y=-2.5
x="$x" y="$y" awk 'BEGIN{ 
        print ENVIRON["x"],ENVIRON["y"];
        if ((ENVIRON["x"] >= 0.1) && (ENVIRON["x"] <= 5.5) \
           && (ENVIRON["y"] >= -5.9) &&  (ENVIRON["y"] <= -0.1)){
              print "good";
        }
        else if ((ENVIRON["x"] >= 5.5) && (ENVIRON["x"] <= 10.5) \
           && (ENVIRON["y"] >= -10.9) &&  (ENVIRON["y"] <= -5.9)){
             print "bad";
        }

}' # End of awk
2
ответ дан 3 December 2019 в 06:29

Другие вопросы по тегам:

Похожие вопросы: