System Status as SMS Text Messages

作者:Dave Taylor

如果您非常关注,您会记得在我的上一篇文章中,我正在探索一个脚本的基本原理,该脚本将接受一个单词列表作为输入,并创建一个单词搜索网格,适合打印。事实证明,作为一个 shell 脚本,这非常难做到——它只是没有足够的能力以优雅的方式实现任何类型的函数式算法。所以,我打算放弃它,至少在我能找到别人的开源代码来激发灵感之前。

或者,当然,如果您有动力并且有一些时间进行实验,请回到我 2015 年 4 月的专栏,通读它,然后尝试自己动手实现一些东西。

在我收到关于作为 shell 脚本编程专栏作家却放弃脚本的奇怪之处的来信之前,我将指出,实际上从这次经历中学到很多东西。最具体地说,虽然想象 Linux 环境是完全平等的,并且每个脚本、每种语言和每个程序都与其他程序一样强大且设计良好,但这显然不是事实。

以 Perl 与 Awk 为例。Awk 功能强大,我经常使用它,但是尽管有使用 Perl 编写的主要软件程序,但您很难找到任何直接用 Awk 编程的重要软件、函数、应用程序或实用程序。C++ 与 PHP 也是如此,或者任何现代结构化语言与 Bourne Again Shell 也是如此。我说出来了。Shell 脚本编程只能带你走这么远,然后你意识到你已经触及了环境及其能力的边缘,现在是时候跳到另一种语言了。

事实上,当我写我广受欢迎的书籍《Wicked Cool Shell Scripts》时,由于必要性,偷偷加入了一个小型 C 程序:它是几行 C 代码,用于执行某个日期计算,如果用 shell 脚本编写,则需要几十行甚至数百行。

话虽如此,我将立即回到为 shell 辩护,认为它是一个功能强大、轻量级的编程和原型设计环境,非常适合各种任务,因为它能够非常轻松地访问整个 Linux 环境以及扩展到整个互联网的强大功能和能力。

您怎么看?您阅读了这个专栏,所以我可以合理地推断您有兴趣了解更多关于 Linux shell 环境中的编程。您多久会碰到 shell 的前沿,并意识到您必须切换到 Perl、Ruby、C、Cobol(开玩笑!)或其他更复杂的开发环境才能正确解决问题?

让我们谈谈短信

我正在观看苹果公司推出新款 Apple Watch,并惊讶地发现,像一些高端 Android 智能手表一样,它会在小小的手表屏幕上显示完整的电子邮件和短信。这意味着对于系统管理员和 Linux IT 人员来说,这是一个很棒的设备,可以随时掌握他们的机器或机器组的状态。

当然,您可以通过让系统发送电子邮件来做到这一点,但让我们更进一步,利用电子邮件到 SMS 网关之一。表 1 显示了美国最常见的蜂窝运营商的网关地址列表。

表 1. 蜂窝运营商的 SMS 网关电子邮件地址
无线运营商 域名
At&T @txt.att.net
Cricket @mms.mycricket.com
Nextel @messaging.nextel.com
Qwest @qwestmp.com
Sprint @messaging.sprintpcs.com
T-Mobile @tmomail.net
US Cellular @email.uscc.net
Verizon @vtext.com
Virgin @vmobl.com

例如,我可以向 AT&T 网络上号码为 (303) 555-1234 的人发送短信,方法是将电子邮件格式化为如下所示


3035551234@txt.att.net

掌握了这些信息后,您可以监控许多不同的状态,并在出现问题时收到简洁的短信。

担心负载平均值变得过高?这是一个可以通过 uptime 的单行输出轻松获得的数字


$  uptime
11:20  up 4 days, 22:44, 3 users, load averages: 1.08 1.40 1.46

最后三个数字是过去 1 分钟、5 分钟和 15 分钟的平均负载。在这种情况下,系统几乎没有被使用。但是,如果它跃升到 10、35 或超过 100 呢?那么一切都会慢下来。以下是如何编写一个简单的脚本来测试这种情况


#!/bin/sh
# loadwatch.sh - send an alert if uptime > MAXOK
MAXOK=10
loadavg=$(uptime | cut -d\   -f11 | cut -d. -f1)
if [ $loadavg -gt $MAXOK ] ; then
  echo "Alert: Load avg $(uptime | cut -d\  -f11)"
fi
exit 0

掌握了有关各种 SMS 网关的信息,很容易硬编码收件人地址,这只会更改条件内的 echo


mail -s "Alert: Load avg $(uptime|cut -d\  -f11)" $recipient

在脚本的早期,“recipient”的格式类似于


recipient=3035551234@txt.att.net

或适合您自己的智能手表或其他设备的格式。

为了使此脚本有用,您可能希望每隔几分钟运行一次,以便在使用量激增时尽快收到警报。这最容易成为 cron 作业,如果您还没有探索您自己的自定义 cron 作业如何使您作为最基本的 Linux 用户的生活变得更好,那么您就错过了!

为了使脚本每十分钟运行一次,以下是它在 root 甚至只是您的用户 crontab 文件中的样子


0,10,20,30,40,50 * * * *  /home/taylor/bin/loadwatch.sh

现代 crontab 具有更复杂的符号语言,可以使其更简洁一些


*/10 * * * *  /home/taylor/bin/loadwatch.sh

为了真正有用,最好让脚本监控状态变化,这样它会在负载升到指定阈值以上时通知您,但在负载降回该阈值以下之前不会再次通知您。

这是通过我们老派程序员所说的信号量来完成的,信号量是一个状态变量,用于记住正在发生的事情。由于 shell 脚本本质上是短暂的,因此信号量需要是一个文件。通常,这些文件位于某种受保护的目录中,但为了演示脚本的目的,我们将其放在您的主目录中。

此时要知道的命令行函数是 lockfile(1)。这管理信号量的原子创建,以便您永远不会遇到所谓的“竞争条件”,即脚本的两个实例可能会在谁创建文件的问题上发生冲突。

以下是它如何与信号量一起工作


statefile=/home/taylor/bin/.loadavg
if [ -f "$statefile" ] ; then
  # statefile already exists, we're in a high load situation
  if [ $loadavg -gt $MAXOK ] ; then
    # still in high load situation
    echo "nothing to do, still in high load situation"
  else
    # high load situation has ended
    /bin/rm -f $statefile
    mail -s "Alert: load average back to normal" $recipient \ 
      < /dev/null > /dev/null 2>&1
  fi
else
  # statefile doesn't exist, let's create it.
  if [ $loadavg -gt $MAXOK ] ; then
    # load average has jumped above OK level
    lockfile $statefile
    load=$(uptime | cut -d\  -f11)
    mail -s "Alert: load average is $load" $recipient \
      < /dev/null > /dev/null 2>&1
  else
    # load average was okay and still is.
    echo "nothing to do, load average still ok."
  fi
fi

当然,在四种可能的情况中有两种情况下,您真的希望删除调试代码,清理 if-then-else 链并缩短脚本,因为如果这要每十分钟运行一次,您肯定不希望生成“no change”消息!

考虑到这一点,以下是更简洁的代码块


if [ -f "$statefile" ] ; then
  # statefile already exists, we're in a high load situation
  if [ $loadavg -le $MAXOK ] ; then
    # high load situation has ended
    /bin/rm -f $statefile
    mail -s "Alert: load average back to normal?" $recipient \
      < /dev/null > /dev/null 2>&1
  fi
else
  # statefile doesn't exist, let's create it.
  if [ $loadavg -gt $MAXOK ] ; then
    # load average has jumped above OK level
    lockfile $statefile
    load=$(uptime | cut -d\  -f11)
    mail -s "Alert: load average is $load?" $recipient \
      < /dev/null > /dev/null 2>&1
  fi
fi

请注意在使用命令行 Mail 程序时涉及的额外工作,您必须重定向输入,以便它不会等待来自 stdin 的消息,并重定向生成的“null message body”警告消息。这就是它的作用


< /dev/null > /dev/null 2>&1

否则,希望您可以通读并了解它的作用。

您还可以监控什么?

当您想到 Linux 系统上可能发生的许多错误时,跟踪负载平均值是相当微不足道的,包括进程被卡住并使用过多的 CPU 时间、磁盘空间可能接近填满、RAM 被耗尽并导致过度交换,甚至未经授权的用户登录。

所有这些情况都可以分析,并且可以通过电子邮件或 SMS 短信向您发送警报,甚至发送到您闪亮的价值 17,000 美元的金色 Apple Watch。现在,您告诉我,您认为您的系统上有什么值得监控的?

Dave Taylor 在 UNIX 和 Linux 系统上编写 shell 脚本已经很长时间了。他是《Learning Unix for Mac OS X》和《Wicked Cool Shell Scripts》的作者。您可以在 Twitter 上通过 @DaveTaylor 找到他,您可以通过他的技术问答网站联系他:Ask Dave Taylor

加载 Disqus 评论