Bash 求值令人困惑

Bash 求值令人困惑

我试图让脚本在一个数字大于另一个数字时执行某些操作,在本例中,就是当系统平均负载超过定义值时。

除了评估标准之外,一切都正常。

当我为一些网站构建另一台服务器时,我试图让 apache 保持一致,原因并不重要,但这个脚本已经在平均负载低于 15 的系统上进行了测试,并且脚本打印出:

“check 为 4.68 且 max 为 15.00”尽管 if 条件告诉它如果 check 的值不大于 max load 则根本不打印任何内容,但事实并非如此。

我不是 bash 专家,我有胡子但没有凉鞋,我尝试了各种不同风格的括号和引号,但我不明白为什么当 $check 小于 $max_load 时这个脚本会打印任何东西。

这是 Debian 6,GNU bash,版本 4.1.5(1)-release-(x86_64-pc-linux-gnu)

#!/bin/bash
check=`cat /proc/loadavg | sed 's/./ /' | awk '{print $2}'`
max_load='15.00';
high_load_log='/var/log/apache2/apache_high_load_restart.log';
apache_init='/etc/init.d/apache2';

if [[ $check > $max_load ]]; then
   echo " check is $check and max is $max_load";
   #$apache_init stop
   sleep 5;
   #$apache_init restart
   echo "$(date) : Apache Restart due to load of | $check |" >> $high_load_log;
fi

在负载约为 4 的系统上,此脚本输出:

"check is 4.68 and max is 15.00"

有人知道为什么吗?

任何有关优质入门凉鞋的帮助和建议都将不胜感激!

答案1

这不会起作用。>里面的运算符[[比较排序,而不是值。所以......

$ echo -e '4.68\n15.00'|sort
15.00
4.68

... 因为 4 排在 1 后面,这意味着[[ 4.68 > 15.00 ]]为真。并且您不能使用-gt,因为这需要整数。

如果你只关心整数阈值,那么这是一个简单的解决方法 — 在 处截断.,使用-gt,就可以了。否则,使用bc— 请参阅https://unix.stackexchange.com/questions/24721/how-to-compare-to-floating-point-number-in-a-shell-script

答案2

根据文档,<>词汇排序。我不确定,但我很确定这与使用类似 得到的结果相同sort。使用 sort 时,15.00是 before,4.68因为它基本上是按字符排序。在大多数语言环境中1都是 before 。4

由于您的示例值4.68将按15.0词汇顺序排序,因此>返回 true。

您几乎肯定希望将字符串视为数字,因此您会使用-gt、 或-lt,但这些仅限于整数。

参考:http://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html

string1 < string2 如果 string1 按字典顺序排列在 string2 之前,则为真。

string1 > string2 如果 string1 按字典顺序排在 string2 之后,则为真。

答案3

谢谢大家,在我的 Debian 系统上运行良好的最终解决方案是这样的,本质上先将其转换为 int,然后使用 -gt。

#!/bin/bash
check=`cat /proc/loadavg | sed 's/ / /' | awk '{print $1}'`
checkint=${check/\.*}
max_load='20';
high_load_log='/var/log/apache2/apache_high_load_restart.log';
apache_init='/etc/init.d/apache2';

if [ $checkint -gt $max_load ]; then
        echo " check is $checkint and max is $max_load";
        $apache_init stop
        sleep 5;
        $apache_init restart
        echo "$(date) : Apache Restart due to excessive load | $check |" >> $high_load_log;
else
        echo "check is $check resolving down to $checkint and max is $max_load - No Action Taken";
fi

答案4

根本问题是 Bash 仅支持整数算术。您可以使用支持浮点的工具来解决这个问题,Awk 就很方便地实现了这一点。

(我还会考虑无用cat并注意这sed | awk同样是无用的。)

awk -v max="$max_load" '$1 > max {
    print "check is " $1 " and max is " max }' /proc/loadavg

如果您想在 shell 条件中使用它,让 Awk 在成功时返回零退出代码,在失败时返回非零退出代码:

if ! check=$(awk -v max="$max_load" '($1 > max) {
       print $1; exit 1 }' /proc/loadavg); then
   echo " check is $check and max is $max_load";
   $apache_init stop
   sleep 5;
   $apache_init restart
   date +"%c : Apache Restart due to load of | $check |" >> $high_load_log;
fi

相关内容