![如果条件在一定范围内(边界)有两个不同的值](https://linux22.com/image/1158044/%E5%A6%82%E6%9E%9C%E6%9D%A1%E4%BB%B6%E5%9C%A8%E4%B8%80%E5%AE%9A%E8%8C%83%E5%9B%B4%E5%86%85%EF%BC%88%E8%BE%B9%E7%95%8C%EF%BC%89%E6%9C%89%E4%B8%A4%E4%B8%AA%E4%B8%8D%E5%90%8C%E7%9A%84%E5%80%BC.png)
假设我有一个坐标 (x,y),我想将其分为两个类别:好或坏。
我不知道如何用文字或关键词来表达它,所以我创建了一个我想要的例子。
我创建了一个这样的 bash 脚本:
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
。使用不同的边界,它应该会给出bad
结果。
我已经运行它并且它给出的结果与预期的整数表达式一致。
当我尝试用运算符-ge
(或-le
)替换运算符>
(或<
),或者尝试添加方括号和任何我能想到的内容时,它会出现相同的错误或没有给出任何结果。
我该如何处理这个问题?
答案1
Bash 只能进行整数运算。如果值的小数位数是固定的,则可以删除.
(使用sed
或awk
或任何您喜欢的命令)并比较结果值。例如,如果它们只有一位小数,如 ,则10.0, 0.4, 2.2
删除.
会将它们乘以十,结果为100, 04, 22
(使用旧的测试命令[
,前导0
s 对于整数比较无关紧要)。当然,您必须相应地乘以边界。
或者,您可以使用bc
,它可以处理任意精度的浮点数。bc
读取stdin
,因此您可以例如回显表达式并将其传输到管道,bc
如下所示:
echo "$x>=0.1 && $x<=5.5" | bc
1
如果表达式为,则输出为true
,0
否则为 。阅读手册(男人 bc) 来了解更多语法。
要将其合并到您的脚本中,您可以使用如下命令替换:
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"
由于括号内难以阅读的字符串更容易出错,因此您可以使用 Bash 函数和变量,如以下示例所示。如果您想添加elif
具有不同范围的附加子句,这可能会很有用。(感谢温德雷亚以获得有用的提示)
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
(感谢钢铁司机):
# 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 ]
}
答案2
如果绝对有必要保留在 shell 脚本中 - 将变量添加到嵌入脚本以将和值awk
传递到 awk 的环境中并使用它们来访问它们;并让它完成打印所需字符串的工作(或将整个脚本包装进去以保存输出)。x
y
ENVIRON["variable_name"]
$(...)
如果没有必要,就省略 shell 脚本部分,只需让 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