bash,如果小数大于,则工作方式很奇怪

bash,如果小数大于,则工作方式很奇怪

我有这个脚本来比较cpuload是否大于限制10

#!/bin/bash

cpuload=$(uptime | cut -d' ' -f 13 | sed '$ s/.$//')
limit=10

echo
echo "cpuload = $cpuload, limit = $limit"
echo

[[ $cpuload > $limit ]] && echo | mail -s "cpuload $cpuload is higher than $limit!" EMAIL

现在,即使价值低于限额,我也会收到电子邮件(3 > 10)

哪里有问题?

我尝试了条件语法的组合,但有时有效,有时无效...我有点困惑。

谢谢。

更新

cpu_load=$(uptime | cut -d' ' -f 13 | sed '$ s/.$//')
limit=1

send_email(){
echo | mail -s "makroczsk, cpuload $cpu_load is higher than limit $limit!" $email_to
}

echo "cpuload = $cpu_load (${cpu_load%%.*}), limit = $limit"

[[ (( ${cpu_load%%.*} > $limit )) ]] && send_email
[[ ${cpu_load%%.*} -gt $limit ]] && send_email
cpuload = 3.10, limit = 10
./check-cpuload.sh: line 9: [[: 3.10: syntax error: invalid arithmetic operator (error token is ".10")

在第一种情况下,电子邮件仍在发送。

更新2

这有效。但我不确定为什么。:/

cpu_load=$(uptime | cut -d' ' -f 13 | sed '$ s/.$//')
limit=1

send_email(){
echo | mail -s "makroczsk, cpuload $cpu_load is higher than limit $limit!" $email_to
}

echo "cpuload = $cpu_load (${cpu_load%%.*}), limit = $limit"

#[[ (( ${cpu_load%%.*} > $limit )) ]] && send_email
[[ ${cpu_load%%.*} -gt $limit ]] && send_email

答案1

您在此处的方法由于多种原因而注定会失败。

首先,即使你获得了算术比较的正确语法,即:

[ $cpuload -gt $limit ]

(兼容 POSIX shell)或

[[ $cpuload -gt $limit ]]

(bash / ksh 扩展测试)或

(( cpuload > limit ))

bash shell 仅支持整数运算,因此您需要先去掉末尾的小数,同时注意您所在语言环境的数字表示形式,正如 HuHa 所提到的

请注意,当你使用[[ $cpuload > $limit ]]它时在 bash 中,这是语法上有效的比较,但它会“奇怪”地工作,因为它按字典顺序逐个字符比较 RHS 和 LHS。特别是,

$ [[ 3.0 > 10.0 ]] && echo greater || echo not greater
greater

因为 character3在字典中大于 character 1;而

$ [[ 03.0 > 10.0 ]] && echo greater || echo not greater
not greater

因为字符0在字典顺序上小于字符1。最重要的是,如果你想在 bash 脚本中执行浮点运算,你将需要一个外部程序,例如bcawkperl。1


其次,uptime输出是为了方便人类阅读,而不是机器解析。具体来说,时间格式会根据实际正常运行时间而变化,例如:

(重启之前)

$ uptime
 10:38:50 up 26 days, 12:33,  4 users,  load average: 0.09, 0.04, 0.00

(重启后)

$ uptime
 10:44:37 up 3 min,  1 user,  load average: 0.17, 0.33, 0.16

尝试对其进行标记cut -d' '特别脆弱,因为它依赖于每个字段的左填充量:例如,如果天数/小时数/分钟数/用户数从个位数变为两位数,它就会失败。

相反,我建议直接从/proc/loadavg-读取平均负载,uptime无论如何,您可以通过以下方式确认strace

$ strace -etrace=openat uptime 2>&1 | tail -n 3
openat(AT_FDCWD, "/proc/loadavg", O_RDONLY) = 4
 12:49:38 up  2:08,  1 user,  load average: 0.00, 0.01, 0.00
+++ exited with 0 +++

格式是简单的空格分隔的字段,您可以轻松解析和测试,awk例如:

$ cat /proc/loadavg
0.52 0.58 0.59 1/5 3759

$ limit=10; awk -v limit="$limit" '$1+0 > limit {exit 1}' /proc/loadavg && echo "ok" || echo "overload"
   ok

$ limit=0.5; awk -v limit="$limit" '$1+0 > limit {exit 1}' /proc/loadavg && echo "ok" || echo "overload"
   overload

笔记:

  1. 当然,你可以切换到支持非整数运算,例如kshzsh

相关内容